2011-12-28 12 views
16

Tengo una lista en C#:¿Hay un método AddUnique similar a AddRange() para la a-lista en C#

 var list = new List<Car>(); 
     list.AddRange(GetGreenCars()); 
     list.AddRange(GetBigCars()); 
     list.AddRange(GetSmallCars()); 

el problema es que algunos de los mismos coches obtener devueltos en diferentes funciones y no hacer los quiero en la lista más de una vez. Cada automóvil tiene un atributo de Nombre único. ¿Hay alguna forma de que pueda tener algo como esto arriba pero solo agregaré elementos si son únicos?

Respuesta

13

Un List<T> no parece ser la recolección apropiado en este caso. Probablemente desee una implementación de ISet<T>, como HashSet<T> (o SortedSet<T> si necesita realizar el pedido).

Para permitir esto, deberá escribir una implementación de IEqualityComparer<T> que defina la igualdad entre los automóviles de acuerdo con la propiedad Name. Si esta es la definición 'canónica' de igualdad de autos, también puede considerar construir directamente esta definición en el tipo Car mismo (object.Equals, object.GetHashCode e idealmente implementar IEquatable<T> también).

30

Una opción es añadir y quitar las repetidas las:

var list = new List<Car>(); 
list.AddRange(GetGreenCars()); 
list.AddRange(GetBigCars()); 
list.AddRange(GetSmallCars()); 
list = list.Distinct().ToList(); 
+0

tengo objetos duplicados dentro de mi colección. Simplemente list = list.Distinct(). ToList(); no funciona – wotney

+2

Distinct eliminará los objetos duplicados. Si sus objetos no son realmente iguales, tiene que hacer que sus objetos implementen Equals() y GetHashCode() – ivowiblo

19

Otra opción es hacer algo como:

public static void AddUnique<T>(this IList<T> self, IEnumerable<T> items) 
{ 
    foreach(var item in items) 
     if(!self.Contains(item)) 
      self.Add(item) 
} 


var list = new List<Car>(); 
list.AddUnique(GetGreenCars()); 
list.AddUnique(GetBigCars()); 
list.AddUnique(GetSmallCars()); 
+0

Simples y agradables. – CmdrTallen

3

Sin embargo, otra opción utilizando LINQ:

public static void AddUnique<T>(this IList<T> self, IEnumerable<T> items) 
{ 
    self.AddRange(
    items.Where(x => self.FirstOrDefault(y => y.Name == x.Name) == 
    null).ToList()); 
} 

var list = new List<Car>(); 
list.AddUnique(GetGreenCars()); 
list.AddUnique(GetBigCars()); 
list.AddUnique(GetSmallCars()); 
8

Creo que esto es bastante similar a la respuesta de Tim Robbins.

var list = new List<Car>(); 
list.AddRange(GetGreenCars().Where(car => !list.Contains(car))); 
list.AddRange(GetBigCars().Where(car => !list.Contains(car))); 
list.AddRange(GetSmallCars().Where(car => !list.Contains(car))); 

Si desea ampliar IList no veo por qué esto no funcionaría para usted.

+0

No olvide reemplazar Igual() y GetHashCode() en el Auto o no coincidirá con el objeto en Contiene(). De lo contrario, mejor respuesta. –

+0

También puede hacer algo como esto para comparar una ID específica dentro del objeto: vm.SearchResults.AddRange (searchResultsOr.Where (listOr =>! SearchResultsAnd.Select (listAnd => listAnd.PostId) .Contains (listOr.PostId))); – Yovav

1

Creé un método de extensión que agrega solo valores únicos a todo lo que implemente ICollection<T> (incluido un List<T>) desde IEnumerable<T>. A diferencia de las implementaciones que usan List<T>.Contains(), este método le permite especificar una expresión lambda que determina si dos elementos son iguales.

/// <summary> 
/// Adds only items that do not exist in source. May be very slow for large collections and some types of source. 
/// </summary> 
/// <typeparam name="T">Type in the collection.</typeparam> 
/// <param name="source">Source collection</param> 
/// <param name="predicate">Predicate to determine whether a new item is already in source.</param> 
/// <param name="items">New items.</param> 
public static void AddUniqueBy<T>(this ICollection<T> source, Func<T, T, bool> predicate, IEnumerable<T> items) 
{ 
    foreach (T item in items) 
    { 
     bool existsInSource = source.Where(s => predicate(s, item)).Any(); 
     if (!existsInSource) source.Add(item); 
    } 
} 

Uso:

source.AddUniqueBy<Foo>((s, i) => s.Id == i.Id, items); 
0

y si se desea comparar una propiedad (id en este caso), esto debería funcionar

var list = new List<string>(); 
list.AddRange(GetGreenCars().Where(greencar => !list.Contains(greencar, car => car.id == greencar.id))); 
list.AddRange(GetBigCars().Where(bigcar => !list.Contains(bigcar, car => car.id == bigcar.id))); 
list.AddRange(GetSmallCars().Where(smallcar => !list.Contains(smallcar, car => car.id == smallcar.id))); 
Cuestiones relacionadas