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;
}
}
Isso se baseia em um exemplo em "LINQ em ação". Listagem 4.16.
Isso imprime Jon Skeet duas vezes. Por quê? Eu até tentei substituir o método Equals na classe Author. Ainda Distinto não parece funcionar. o que estou perdendo?
Editar: Eu adicionei == e! = Sobrecarga de operador também. Ainda sem ajuda.
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
fonte
fonte
IEquatable
(e substituíEquals
/GetHashCode
), mas nenhum dos meus pontos de interrupção está disparando nesses métodos em um LinqDistinct
?GetHashCode
eEquals
, eles foram atingidos durante o loop foreach. Isso porque ovar temp = books.SelectMany(book => book.Authors).Distinct();
retorna umIEnumerable
, significando que a solicitação não é executada imediatamente, ela só é executada quando os dados são utilizados. Se você quiser um exemplo desse disparo imediatamente, adicione.ToList()
após o.Distinct()
e verá os pontos de interrupção noEquals
eGetHashCode
antes do foreach.O
Distinct()
método verifica a igualdade de referência para tipos de referência. Isso significa que ele está procurando literalmente o mesmo objeto duplicado, não objetos diferentes que contêm os mesmos valores.Há uma sobrecarga que leva um IEqualityComparer , portanto, você pode especificar uma lógica diferente para determinar se um determinado objeto é igual a outro.
Se você deseja que Author normalmente se comporte como um objeto normal (ou seja, apenas referência de igualdade), mas para fins de verificação de igualdade distinta por valores de nome, use um IEqualityComparer . Se você sempre deseja que os objetos Author sejam comparados com base nos valores de nome, substitua GetHashCode e Equals ou implemente IEquatable .
Os dois membros da
IEqualityComparer
interface sãoEquals
eGetHashCode
. Sua lógica para determinar se doisAuthor
objetos são iguais parece ser se as strings de nome e sobrenome forem iguais.fonte
Outra solução sem implementação
IEquatable
,Equals
eGetHashCode
é usar oGroupBy
método LINQs e selecionar o primeiro item do IGrouping.fonte
.GroupBy(y => new { y.FirstName, y.LastName })
Há mais uma maneira de obter valores distintos da lista de tipos de dados definidos pelo usuário:
Certamente, fornecerá um conjunto distinto de dados
fonte
Distinct()
executa a comparação de igualdade padrão em objetos no enumerável. Se você não substituiuEquals()
eGetHashCode()
, ele usa a implementação padrão emobject
, que compara as referências.A solução simples é adicionar uma implementação correta de
Equals()
eGetHashCode()
para todas as classes que participam do gráfico de objeto que você está comparando (isto é, Livro e Autor).A
IEqualityComparer
interface é uma conveniência que permite a você implementarEquals()
eGetHashCode()
em uma classe separada quando você não tem acesso aos detalhes internos das classes que precisa comparar, ou se estiver usando um método diferente de comparação.fonte
Você substituiu Equals (), mas certifique-se de também substituir GetHashCode ()
fonte
<custom>^base.GetHashCode()
As respostas acima estão erradas !!! Distinto, conforme declarado no MSDN, retorna o Equador padrão que, conforme declarado, A propriedade Default verifica se o tipo T implementa a interface System.IEquatable e, em caso afirmativo, retorna um EqualityComparer que usa essa implementação. Caso contrário, ele retorna um EqualityComparer que usa as substituições de Object.Equals e Object.GetHashCode fornecidos por T
O que significa que enquanto você ignorar Igual a você está bem.
O motivo pelo qual seu código não está funcionando é porque você verificou firstname == lastname.
consulte https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx e https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx
fonte
Você pode usar o método de extensão na lista que verifica a exclusividade com base no Hash calculado. Você também pode alterar o método de extensão para oferecer suporte a IEnumerable.
Exemplo:
Método de extensão:
fonte
Você pode conseguir isso de duas maneiras:
1. Você pode implementar a interface IEquatable como mostrado pelo Método Enumerable.Distinct ou pode ver a resposta de @ skalb neste post
2. Se o seu objeto não possui uma chave única, você pode usar o método GroupBy para obter uma lista de objetos distintos, que deve agrupar todas as propriedades do objeto e após selecionar o primeiro objeto.
Por exemplo, como abaixo e trabalhando para mim:
A classe MyObject é como a seguir:
3. Se o seu objeto tiver uma chave exclusiva, você só poderá usá-lo no grupo por.
Por exemplo, a chave exclusiva do meu objeto é Id.
fonte