2009-04-30 29 views
15

Quiero obtener la diferencia entre dos conjuntos de entradas en C#. Dado s1 y s2 quiero devolver esas entradas que están en s1 y no en s2. Puedo hacer algo como:¿Hay alguna manera de obtener la diferencia entre dos conjuntos de objetos en C#

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 puede señalar algo más limpio. Me gustaría hacer algo como

List<int> omitted = s1.Difference(s2); 
No

seguro si hay un método existente o una construcción de LINQ que cualquier persona puede ser capaz de señalar? Gracias.

Respuesta

18

Creo que quieres HashSet.Except. Es decir, en lugar de usar Listas, use HashSets y luego la operación estará disponible. Este es un tipo mejor si lo que estás representando es realmente un 'conjunto' de todos modos. (Si ya tiene una lista, sólo puede crear un 'nuevo HashSet' fuera de él.)

+0

awesome thankyou. Excepto() es el método que estaba buscando y tomo su consejo sobre HashSets. – SiC

+0

Excepto que es una función de extensión, ¿no? – leppie

+0

Hay un método de extensión Enumerable.Except para todos los IEnumerables. Pero HashSet tiene un método Excepto específicamente para HashSets. – Brian

1
 
from x in s1 
where ! s2.contains(x) 
select x 
2
List<int> s1 = new List<int>(); 
List<int> s2 = new List<int>(); 

return sl.FindAll(i => !s2.Contains(i)) 
20
IEnumerable<T> a, b; 

var added = a.Except(b); 
var removed = b.Except(a); 
+1

Tenga en cuenta que esto usa Enumerable.Except, por lo que debe usar System.Linq. http://msdn.microsoft.com/en-us/library/bb300779.aspx – Brian

+0

¿Eso es un problema? :) – leppie

+1

¿Problema? No, solo quería ayudar a alguien que podría cortar y pegar este código y descubrir que no compila. – Brian

0

Aquí son dos métodos de extensión que pueden venir muy útil cuando se necesita encontrar desordenada diferencias entre dos IEnumerable (es más o menos lo mismo que la respuesta dada por el envoltorio de 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(); 
    } 
} 
Cuestiones relacionadas