2011-05-13 32 views

Respuesta

13

Esto debe hacerlo:

list1.Union(list2).Distinct(aCustomComparer).ToList() 
+0

¿No es redundante utilizar distintos() después de Union()? – 0xbadf00d

+2

Depende de las condiciones de la unión. De forma predeterminada, el método Union() solo deduplicará los objetos que son de la misma referencia. Dado que Distinct está utilizando un IEqualityComparer personalizado, en realidad hará algo más que la unión.PERO, que IEqualityComparer también puede ser entregado directamente a la Unión para su uso como deducidor, por lo que es ligeramente redundante. – KeithS

+0

'Union' usa el comparador de igualdad predeterminado, que, dependiendo del tipo, puede o no ser un comparador de referencia. Consulte https://msdn.microsoft.com/en-us/library/vstudio/bb341731(v=vs.100).aspx y https://msdn.microsoft.com/en-us/library/vstudio/bb341731 (v = vs.100) .aspx. Además, como mencionó, es mejor proporcionar el comparador personalizado al método 'Unión 'y eliminar la llamada' Distinct' para legibilidad y (¿quizás?) Una ganancia de rendimiento leve. –

6

Como siempre y cuando estén IEnumerable, se puede utilizar el go-to respuesta LINQ:

var union = firstCollection.Union(secondCollection); 

Este utilizará la comparación de igualdad predeterminada, que para la mayoría de los objetos es la igualdad referencial. Para cambiar esto, puede definir un IEqualityComparer genérico para el tipo de elemento en su colección que realizará una comparación más semántica, y especificarlo como el segundo argumento de la Unión.

2

otra forma de agregar a su lista de exisiting sería:

list1.AddRange(list2.Distinct().Except(list1)); 
+0

Esto es básicamente la operación detrás de Union(), BTW. el iterador Except() básicamente invocará Any (x => x == Current) en la lista pasada1 y devolverá elementos de list2 donde es falso. – KeithS

+0

Excepto que union no modifica la lista original, se solicitó OP para 'agregar elementos distintos de un segundo ICollection a uno existente', Union devuelve una nueva colección. –

+0

Mi respuesta puede no ser lo que el OP quería, pero su pregunta es lo suficientemente ambigua como para ser. –

2

La respuesta más directa a su pregunta - ya que no dio muchos detalles sobre los tipos reales de ICollection que tiene como entrada o necesidad ya que la producción es la dada por Keiths

var union = firstCollection.Union(secondCollection); 

Esto devuelve un IEnumerable distinta - si eso es lo que necesita, entonces es muy rápido. Hice una pequeña aplicación de prueba (a continuación) que ejecutó el método de unión (MethodA) contra un simple método hashset de deduplicación y devuelve un Hashset <> (MethodB). El método de unión destruye la hashset:

MethodA: 1 ms

MethodB: 2827ms

Sin embargo - Tener que convertir ese IEnumerable a algún otro tipo de colección como la lista <> (como la ADAS versión publicada) cambia todo:

Simplemente añadiendo .ToList() para MethodA

var union = firstCollection.Union(secondCollection).ToList(); 

Cambia los resultados:

MethodA: 3656ms

MethodB: 2803ms

Por lo tanto - parece más tendría que ser conocido por el caso específico que está trabajando - y cualquier la solución que se le ocurra debería probarse, ya que un cambio pequeño (de código) puede tener GRANDES impactos.

A continuación se muestra la prueba solía comparar estos métodos - Estoy seguro de que es una forma estúpida de prueba - pero parece que funciona :)

private static void Main(string[] args) 
    { 
     ICollection<string> collectionA = new List<string>(); 
     ICollection<string> collectionB = new List<string>(); 
     for (int i = 0; i < 1000; i++) 
     { 
      string randomString = Path.GetRandomFileName(); 
      collectionA.Add(randomString); 
      collectionA.Add(randomString); 
      collectionB.Add(randomString); 
      collectionB.Add(randomString); 
     } 
     Stopwatch testA = new Stopwatch(); 
     testA.Start(); 
     MethodA(collectionA, collectionB); 
     testA.Stop(); 


     Stopwatch testB = new Stopwatch(); 
     testB.Start(); 
     MethodB(collectionA, collectionB); 
     testB.Stop(); 

     Console.WriteLine("MethodA: {0}ms", testA.ElapsedMilliseconds); 
     Console.WriteLine("MethodB: {0}ms", testB.ElapsedMilliseconds); 
     Console.ReadLine(); 
    } 

    private static void MethodA(ICollection<string> collectionA, ICollection<string> collectionB) 
    { 
     for (int i = 0; i < 10000; i++) 
     { 
      var result = collectionA.Union(collectionB); 
     } 
    } 

    private static void MethodB(ICollection<string> collectionA, ICollection<string> collectionB) 
    { 
     for (int i = 0; i < 10000; i++) 
     { 
      var result = new HashSet<string>(collectionA); 
      foreach (string s in collectionB) 
      { 
       result.Add(s); 
      } 
     } 
    } 
+0

Solo para ser claro; SIEMPRE hay una solución más eficaz que Linq. Sin embargo, para el 99.9% de lo que programarías en .NET para empezar (a diferencia de un lenguaje más nativo que hará volar cualquier implementación de .NET), Linq está bien en el rendimiento y generalmente es la implementación más legible y comprensible. . – KeithS

+0

La razón por la cual MethodA es mucho más rápido es porque no enumera los elementos de la colección que devuelve, esta es la razón por la que llamar a ToList lo hace mucho más lento. –

Cuestiones relacionadas