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;
}
}
이것은 “LINQ in Action”의 예를 기반으로합니다. 목록 4.16.
이것은 Jon Skeet을 두 번 인쇄합니다. 왜? Author 클래스에서 Equals 메서드를 재정의하려고 시도했습니다. 여전히 Distinct가 작동하지 않는 것 같습니다. 내가 무엇을 놓치고 있습니까?
편집 : 나는 == 및! = 연산자 과부하도 추가했습니다. 여전히 도움이되지 않습니다.
public static bool operator ==(Author a, Author b)
{
return true;
}
public static bool operator !=(Author a, Author b)
{
return false;
}
답변
LINQ Distinct는 사용자 지정 개체와 관련하여 그다지 똑똑하지 않습니다.
목록을보고 두 개의 다른 개체가 있는지 확인하기 만하면됩니다 (구성원 필드에 대해 동일한 값이 있는지 상관하지 않습니다).
한 가지 해결 방법은 여기에 표시된대로 IEquatable 인터페이스를 구현하는 것 입니다.
이렇게 Author 클래스를 수정하면 작동합니다.
public class Author : IEquatable<Author>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Equals(Author other)
{
if (FirstName == other.FirstName && LastName == other.LastName)
return true;
return false;
}
public override int GetHashCode()
{
int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();
int hashLastName = LastName == null ? 0 : LastName.GetHashCode();
return hashFirstName ^ hashLastName;
}
}
답변
이 Distinct()
메서드는 참조 유형에 대한 참조 동등성을 확인합니다. 즉, 동일한 값을 포함하는 다른 개체가 아니라 문자 그대로 복제 된 동일한 개체를 찾습니다.
IEqualityComparer를 사용 하는 오버로드 가 있으므로 주어진 개체가 다른 개체와 같은지 여부를 결정하기 위해 다른 논리를 지정할 수 있습니다.
Author가 일반적으로 일반 객체처럼 동작하도록하려면 (즉, 참조 같음 만), Distinct의 목적으로 이름 값으로 같음을 확인하려면 IEqualityComparer를 사용하십시오 . 항상 Author 개체를 이름 값을 기준으로 비교하려면 GetHashCode 및 Equals 를 재정의 하거나 IEquatable을 구현하십시오 .
IEqualityComparer
인터페이스 의 두 멤버 는 Equals
및 GetHashCode
입니다. 두 Author
개체가 같은지 여부를 결정하는 논리는 이름 및 성 문자열이 동일한 경우로 나타납니다.
public class AuthorEquals : IEqualityComparer<Author>
{
public bool Equals(Author left, Author right)
{
if((object)left == null && (object)right == null)
{
return true;
}
if((object)left == null || (object)right == null)
{
return false;
}
return left.FirstName == right.FirstName && left.LastName == right.LastName;
}
public int GetHashCode(Author author)
{
return (author.FirstName + author.LastName).GetHashCode();
}
}
답변
구현해야만 용액 IEquatable
, Equals
및 GetHashCode
LINQs 사용하는 GroupBy
방법 및 IGrouping 중 첫 번째 항목을 선택한다.
var temp = books.SelectMany(book => book.Authors)
.GroupBy (y => y.FirstName + y.LastName )
.Select (y => y.First ());
foreach (var author in temp){
Console.WriteLine(author.FirstName + " " + author.LastName);
}
답변
사용자 정의 데이터 유형 목록에서 고유 한 값을 가져 오는 또 다른 방법이 있습니다.
YourList.GroupBy(i => i.Id).Select(i => i.FirstOrDefault()).ToList();
확실히, 그것은 별개의 데이터 세트를 제공 할 것입니다
답변
Distinct()
열거 형의 개체에 대한 기본 같음 비교를 수행합니다. Equals()
및을 재정의하지 않은 경우 GetHashCode()
에 기본 구현을 사용합니다.object
참조를 비교 .
간단한 솔루션은 추가하는 것입니다 올바른 구현을 Equals()
하고GetHashCode()
있습니다 (예 : 도서 및 저자)를 비교하는 객체 그래프에 참여하는 모든 클래스를.
IEqualityComparer
인터페이스를 구현할 수있는 편리 Equals()
하고 GetHashCode()
별도의 클래스에서 당신이 비교의 다른 방법을 사용하는 경우 비교해야하거나 클래스의 내부에 액세스 할 수없는 경우.
답변
Equals ()를 재정의했지만 GetHashCode ()도 재정의했는지 확인하십시오.
답변
위의 답변이 잘못되었습니다 !!! MSDN에 명시된 Distinct는 명시된대로 기본 Equator를 반환합니다 . Default 속성은 T 유형이 System.IEquatable 인터페이스를 구현하는지 여부를 확인하고, 그렇다면 해당 구현을 사용하는 EqualityComparer를 반환합니다. 그렇지 않으면 T에서 제공하는 Object.Equals 및 Object.GetHashCode의 재정의를 사용하는 EqualityComparer를 반환합니다.
즉, Equals를 오버라이드하는 한 괜찮습니다.
코드가 작동하지 않는 이유는 firstname == lastname을 확인하기 때문입니다.
참조 https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx 및 https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx