class Program
{
static void Main(string[] args)
{
List<Book> books = new List<Book>
{
new Book
{
Name="C# in Depth",
Authors = new List<Author>
{
new Author
{
FirstName = "Jon", LastName="Skeet"
},
new Author
{
FirstName = "Jon", LastName="Skeet"
},
}
},
new Book
{
Name="LINQ in Action",
Authors = new List<Author>
{
new Author
{
FirstName = "Fabrice", LastName="Marguerie"
},
new Author
{
FirstName = "Steve", LastName="Eichert"
},
new Author
{
FirstName = "Jim", LastName="Wooley"
},
}
},
};
var temp = books.SelectMany(book => book.Authors).Distinct();
foreach (var author in temp)
{
Console.WriteLine(author.FirstName + " " + author.LastName);
}
Console.Read();
}
}
public class Book
{
public string Name { get; set; }
public List<Author> Authors { get; set; }
}
public class Author
{
public string FirstName { get; set; }
public string LastName { get; set; }
public override bool Equals(object obj)
{
return true;
//if (obj.GetType() != typeof(Author)) return false;
//else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;
}
}
Esto se basa en un ejemplo de "LINQ en acción". Listado 4.16.
Esto imprime a Jon Skeet dos veces. ¿Por qué? Incluso he intentado anular el método Equals en la clase Author. Still Distinct no parece funcionar. ¿Qué me estoy perdiendo?
Editar: también he agregado == y! = Sobrecarga del operador. Sigo sin ayuda.
public static bool operator ==(Author a, Author b)
{
return true;
}
public static bool operator !=(Author a, Author b)
{
return false;
}
c#
.net
linq
iequatable
iequalitycomparer
Tanmoy
fuente
fuente
IEquatable
(y anuléEquals
/GetHashCode
) pero ninguno de mis puntos de interrupción se activa en estos métodos en un LinqDistinct
.GetHashCode
yEquals
, fueron golpeados durante el bucle foreach. Esto se debe a quevar temp = books.SelectMany(book => book.Authors).Distinct();
devuelve unIEnumerable
, lo que significa que la solicitud no se ejecuta de inmediato, solo se ejecuta cuando se utilizan los datos. Si desea un ejemplo de este disparo de inmediato, agregue.ToList()
después de.Distinct()
y verá los puntos de interrupción enEquals
yGetHashCode
antes de foreach.El
Distinct()
método verifica la igualdad de referencia para los tipos de referencia. Esto significa que está buscando literalmente el mismo objeto duplicado, no diferentes objetos que contengan los mismos valores.Hay una sobrecarga que toma IEqualityComparer , por lo que puede especificar una lógica diferente para determinar si un objeto dado es igual a otro.
Si desea que Author se comporte normalmente como un objeto normal (es decir, solo la igualdad de referencia), pero para los propósitos de Distinct comprobar la igualdad por valores de nombre, use un IEqualityComparer . Si siempre desea que los objetos de Autor se comparen en función de los valores de nombre, anule GetHashCode y Equals , o implemente IEquatable .
Los dos miembros de la
IEqualityComparer
interfaz sonEquals
yGetHashCode
. Su lógica para determinar si dosAuthor
objetos son iguales parece ser si las cadenas de nombre y apellido son iguales.fuente
Otra solución sin implementar
IEquatable
,Equals
yGetHashCode
es utilizar la LINQsGroupBy
método y para seleccionar el primer elemento de la IGrouping.fuente
.GroupBy(y => new { y.FirstName, y.LastName })
Hay una forma más de obtener valores distintos de la lista de tipos de datos definidos por el usuario:
Seguramente, dará un conjunto de datos distinto
fuente
Distinct()
realiza la comparación de igualdad predeterminada en objetos en el enumerable. Si no ha anuladoEquals()
yGetHashCode()
, entonces usa la implementación predeterminada enobject
, que compara referencias.La solución simple es agregar una implementación correcta de
Equals()
yaGetHashCode()
todas las clases que participan en el gráfico de objetos que está comparando (es decir, Libro y Autor).La
IEqualityComparer
interfaz es una conveniencia que le permite implementarEquals()
yGetHashCode()
en una clase separada cuando no tiene acceso a las partes internas de las clases que necesita comparar, o si está utilizando un método de comparación diferente.fuente
Has anulado Equals (), pero asegúrate de anular también GetHashCode ()
fuente
<custom>^base.GetHashCode()
¡Las respuestas anteriores son incorrectas! Distinto, como se indica en MSDN, devuelve el Equator predeterminado que, como se indica, la propiedad predeterminada comprueba si el tipo T implementa la interfaz System.IEquatable y, de ser así, devuelve un EqualityComparer que usa esa implementación. De lo contrario, devuelve un EqualityComparer que utiliza las anulaciones de Object.Equals y Object.GetHashCode proporcionadas por T
Lo que significa que siempre que anule Equals, está bien.
La razón por la que su código no funciona es porque marca el nombre == apellido.
ver https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx y https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx
fuente
Puede usar el método de extensión en la lista que verifica la unicidad según el Hash calculado. También puede cambiar el método de extensión para admitir IEnumerable.
Ejemplo:
Método de extensión:
fuente
Puede lograr esto de dos formas:
1. Puede implementar la interfaz IEquatable como se muestra en el método Enumerable.Distinct o puede ver la respuesta de @ skalb en esta publicación
2. Si su objeto no tiene una clave única, puede usar el método GroupBy para lograr una lista de objetos distintos, que debe agrupar todas las propiedades del objeto y luego seleccionar el primer objeto.
Por ejemplo, como a continuación y trabajando para mí:
La clase MyObject es como la siguiente:
3. Si su objeto tiene una clave única, solo puede usarlo en el grupo.
Por ejemplo, la clave única de mi objeto es Id.
fuente