2012-08-04 17 views
19

Tengo un list<message> que contiene propiedades del tipo Guid y DateTime (así como otras propiedades). Me gustaría deshacerme de todos los elementos de esa lista donde Guid y DateTime son iguales (excepto uno). Habrá ocasiones en que esas dos propiedades será el mismo que otros elementos de la lista, pero las otras propiedades serán diferentes, por lo que no sólo puede utilizar .Distinct()Seleccionar distinto por dos propiedades en una lista

List<Message> messages = GetList(); 
//The list now contains many objects, it is ordered by the DateTime property 

messages = from p in messages.Distinct( what goes here?); 

Esto es lo que tengo en este momento, pero parece que debe haber una mejor manera

List<Message> messages = GetList(); 

for(int i = 0; i < messages.Count() - 1) //use Messages.Count() -1 because the last one has nothing after it to compare to 
{ 
    if(messages[i].id == messages[i+1}.id && messages[i].date == message[i+1].date) 
    { 
     messages.RemoveAt(i+1); 
    { 
    else 
    { 
     i++ 
    } 
} 
+1

http://stackoverflow.com/questions/489258/linq-distinct-on-a-particular-property – Shyju

+0

Gracias. No sé por qué no pude encontrar eso cuando busqué. – user1304444

+0

Me alegra que la respuesta de Jon haya funcionado para ti. Solo una nota de precaución: su "método utilizado actualmente" no se compila y (después de corregir los errores de compilación) no funcionará en todos los casos: según el orden de los elementos, se obtendría diferente ** (error ** resultados (después de todo, solo comparas elementos adyacentes entre sí). – Adam

Respuesta

52

LINQ a objetos no proporciona esta funcionalidad fácilmente de una manera integrada, pero MoreLINQ tiene un práctico método DistinctBy:

messages = messages.DistinctBy(m => new { m.id, m.date }).ToList(); 
+0

Supongo que MoreLINQ es de uso gratuito? No veo eso explícitamente escrito en ninguna parte de la página. – user1304444

+2

@ user1304444: es una biblioteca de código abierto; consulte el enlace "Apache License 2.0" a la izquierda de la página. –

+3

Para cualquier persona que vea esta pregunta, el enlace mencionado anteriormente Shyju parece ser una gran respuesta también. http://stackoverflow.com/questions/489258/linq-distinct-on-a-particular-property – user1304444

2

¿Qué tal esto?

var messages = messages 
       .GroupBy(m => m.id) 
       .GroupBy(m => m.date) 
       .Select(m => m.First()); 
+0

no se compila ... Recuerde que GroupBy devuelve un 'IGrouping'. – Adam

+0

Este enfoque es válido si HashSet no está disponible en la placa que está desarrollando como silverslight .... – Thomas

11

Jon Skeet de DistinctBy es definitivamente el camino a seguir, sin embargo, si usted está interesado en la definición de su propio método de extensión que podría tomar de fantasía en esta versión más concisa:

public static IEnumerable<TSource> DistinctBy<TSource, TKey> 
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) 
{ 
    var known = new HashSet<TKey>(); 
    return source.Where(element => known.Add(keySelector(element))); 
} 

que tiene la misma firma :

messages = messages.DistinctBy(x => new { x.id, x.date }).ToList(); 
+2

Sé que esto es antiguo, pero tenga en cuenta que debe llamar a 'ToList()' o 'ToArray()' después de llamar a 'DistinctBy()'. Si trabaja directamente en 'IEnumerable' y lo enumera varias veces, no funcionará, ya que los elementos se agregan al' HashSet' mientras pasa por 'IEnumerable' la primera vez y no se devolverán por segunda vez, como se muestra en este [.NET Fiddle] (https://dotnetfiddle.net/5PUJxl). – fknx

1

Se puede extraer de mi biblioteca PowerfulExtensions. Actualmente se encuentra en una etapa muy joven, pero ya puedes usar métodos como Distinct, Union, Intersect, excepto en cualquier cantidad de propiedades;

Esta es la forma en que lo utilice:

using PowerfulExtensions.Linq; 
... 
var distinct = myArray.Distinct(x => x.A, x => x.B); 
Cuestiones relacionadas