LINQ: valores distintos

Tengo el siguiente conjunto de elementos de un XML:

id category 5 1 5 3 5 4 5 3 5 3 

Necesito una lista distinta de estos elementos:

 5 1 5 3 5 4 

¿Cómo puedo distinguir para Category AND Id también en LINQ?

¿Estás tratando de ser distinto por más de un campo? Si es así, solo use un tipo anónimo y el operador Distinct y debería estar bien:

 var query = doc.Elements("whatever") .Select(element => new { id = (int) element.Attribute("id"), category = (int) element.Attribute("cat") }) .Distinct(); 

Si intenta obtener un conjunto distinto de valores de un tipo “más grande”, pero solo observa un subconjunto de propiedades para el aspecto de distinción, probablemente desee DistinctBy tal como se implementó en MoreLINQ en DistinctBy.cs :

  public static IEnumerable DistinctBy( this IEnumerable source, Func keySelector, IEqualityComparer comparer) { HashSet knownKeys = new HashSet(comparer); foreach (TSource element in source) { if (knownKeys.Add(keySelector(element))) { yield return element; } } } 

(Si pasa null como comparador, usará el comparador predeterminado para el tipo de clave).

Simplemente use Distinct() con su propio comparador.

http://msdn.microsoft.com/en-us/library/bb338049.aspx

Además de la respuesta de Jon Skeet, también puede usar el grupo por expresiones para obtener los grupos únicos a lo largo del recuento de w / a para las iteraciones de cada grupo:

 var query = from e in doc.Elements("whatever") group e by new { id = e.Key, val = e.Value } into g select new { id = g.Key.id, val = g.Key.val, count = g.Count() }; 

Para cualquiera que todavía esté mirando; Aquí hay otra forma de implementar un comparador lambda personalizado.

 public class LambdaComparer : IEqualityComparer { private readonly Func _expression; public LambdaComparer(Func lambda) { _expression = lambda; } public bool Equals(T x, T y) { return _expression(x, y); } public int GetHashCode(T obj) { /* If you just return 0 for the hash the Equals comparer will kick in. The underlying evaluation checks the hash and then short circuits the evaluation if it is false. Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects), you will always fall through to the Equals check which is what we are always going for. */ return 0; } } 

a continuación, puede crear una extensión para el linq Distinct que puede tomar en lambda

  public static IEnumerable Distinct(this IEnumerable list, Func lambda) { return list.Distinct(new LambdaComparer(lambda)); } 

Uso:

 var availableItems = list.Distinct((p, p1) => p.Id== p1.Id); 

Llego un poco tarde a la respuesta, pero es posible que desee hacerlo si desea el elemento completo, no solo los valores que desea agrupar:

 var query = doc.Elements("whatever") .GroupBy(element => new { id = (int) element.Attribute("id"), category = (int) element.Attribute("cat") }) .Select(e => e.First()); 

Esto le dará el primer elemento completo que coincida con su grupo por selección, al igual que el segundo ejemplo de Jon Skeets usando DistinctBy, pero sin implementar el comparador de igualdad de resultados de IE. DistinctBy probablemente sea más rápido, pero la solución anterior implicará menos código si el rendimiento no es un problema.

 // First Get DataTable as dt // DataRowComparer Compare columns numbers in each row & data in each row IEnumerable Distinct = dt.AsEnumerable().Distinct(DataRowComparer.Default); foreach (DataRow row in Distinct) { Console.WriteLine("{0,-15} {1,-15}", row.Field(0), row.Field(1)); } 

Ya que estamos hablando de tener cada elemento exactamente una vez, un “conjunto” tiene más sentido para mí.

Ejemplo con clases e IEqualityComparer implementado:

  public class Product { public int Id { get; set; } public string Name { get; set; } public Product(int x, string y) { Id = x; Name = y; } } public class ProductCompare : IEqualityComparer { public bool Equals(Product x, Product y) { //Check whether the compared objects reference the same data. if (Object.ReferenceEquals(x, y)) return true; //Check whether any of the compared objects is null. if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) return false; //Check whether the products' properties are equal. return x.Id == y.Id && x.Name == y.Name; } public int GetHashCode(Product product) { //Check whether the object is null if (Object.ReferenceEquals(product, null)) return 0; //Get hash code for the Name field if it is not null. int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode(); //Get hash code for the Code field. int hashProductCode = product.Id.GetHashCode(); //Calculate the hash code for the product. return hashProductName ^ hashProductCode; } } 

Ahora

 List originalList = new List {new Product(1, "ad"), new Product(1, "ad")}; var setList = new HashSet(originalList, new ProductCompare()).ToList(); 

setList tendrá elementos únicos

Pensé en esto mientras trataba con .Except() que devuelve una diferencia de conjunto