c# - simetrica - realizar un programa en c para obtener la unión intersección y diferencia de dos conjuntos ayb
¿Hay una manera de obtener la diferencia entre dos conjuntos de objetos en c# (6)
Quiero obtener la diferencia entre dos conjuntos de entradas en c #. Dado s1 y s2 quiero devolver esos ints que están en s1 y no en s2. Puedo hacer algo como:
List<int> s1 = new List<int>();
List<int> s2 = new List<int>();
foreach (int i in s1)
{
if (s1.Contains(i))
{
//
}
else
{
//
}
}
Pero me preguntaba si alguien podría señalar algo más limpio. Me gustaría hacer algo como
List<int> omitted = s1.Difference(s2);
¿No está seguro si hay un método existente o una construcción LINQ que alguien pueda señalar? Gracias.
Aquí hay dos métodos de extensión que pueden ser útiles cuando necesita encontrar diferencias no ordenadas entre dos IEnumerables (es más o menos lo mismo que la respuesta dada por el envoltorio leppie en los métodos de extensión):
public class EnumerableDifferences<T>
{
public IEnumerable<T> Added { get; }
public IEnumerable<T> Removed { get; }
public EnumerableDifferences(IEnumerable<T> added, IEnumerable<T> removed)
{
Added = added;
Removed = removed;
}
}
public static class EnumerableExtensions
{
public static HashSet<TSource> ToHashSet<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
{
return new HashSet<TSource>(source, comparer);
}
public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> keyComparer = null)
{
return first
.ExceptBy(keySelector, second.Select(keySelector), keyComparer);
}
public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEnumerable<TKey> keys, IEqualityComparer<TKey> keyComparer = null)
{
var secondKeys = keys.ToHashSet(keyComparer);
foreach (var firstItem in source)
{
var firstItemKey = keySelector(firstItem);
if (!secondKeys.Contains(firstItemKey))
{
yield return firstItem;
}
}
}
public static EnumerableDifferences<TSource> DifferencesBy<TSource, TKey>(this IEnumerable<TSource> first, IEnumerable<TSource> second, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> keyComparer = null)
{
keyComparer = keyComparer ?? EqualityComparer<TKey>.Default;
var removed = first.ExceptBy(second, keySelector, keyComparer);
var added = second.ExceptBy(first, keySelector, keyComparer);
var result = new EnumerableDifferences<TSource>(added, removed);
return result;
}
public static EnumerableDifferences<TSource> Differences<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer = null)
{
return first
.DifferencesBy(second, x => x, comparer);
}
}
public static class Program
{
public static void Main(params string[] args)
{
var l1 = new[] { ''a'', ''b'', ''c'' };
var l2 = new[] { ''a'', ''d'', ''c'' };
var result = l1.Differences(l2);
Console.ReadKey();
}
}
Creo que quieres HashSet.Except . Es decir, en lugar de usar Listas, use HashSets, y entonces la operación está disponible. Este es un tipo mejor si lo que está representando es realmente un ''conjunto'' de todos modos. (Si ya tiene una lista, solo puede crear un ''HashSet nuevo'' a partir de ella).
Otra API útil, consigue la diferencia simétrica:
IEnumerable<T> a, b;
var added = a.Except(b);
var removed = b.Except(a);
List<int> s1 = new List<int>();
List<int> s2 = new List<int>();
return sl.FindAll( i => !s2.Contains(i) )
from x in s1 where ! s2.contains(x) select x