Distinct()
정의
namespace : Systme.Linq
assembly : Systme.Linq.dll
시퀀스의 고유 요소를 반환한다.
Overloads
Distinct<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>) | 지정된 IEqualityComparer<T>로 값을 비교(필터)하여 시퀀스에서 고유 요소를 반환된다. |
Distinct<TSource>(IEnumerable<TSource>) | 기본 '같음' 비교자로 값을 비교하여 시퀀스에서 고유 요소를 반환한다. |
❗비교값 반환 시 첫 번째 값이 반환된다.
⭐지연실행
Distinct<TSource>(IEnumerable<TSource>, IEqualityComparer<TSource>)
지정된 IEqualityComparer<T>로 값을 비교(필터)하여 시퀀스에서 교유 요소를 반환한다.
public static System.Collections.Generic.IEnumerable<TSource> Distinct<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, System.Collections.Generic.IEqualityComparer<TSource>? comparer);
예제
public class School
{
public string Name { get; set; }
public string Address { get; set; }
}
public class CustomSchoolEqualityComparer : IEqualityComparer<School>
{
// 반환(필터) 하고자 하는 로직 구성
public bool Equals(School? x, School? y)
{
if(x.Name.Equals(y.Name)) return true;
else return false;
}
// Equals() 가 true를 반환하면 GetGashCode()는 해당 객체에 대해 동일한 값을 반환해야 한다.
public int GetHashCode([DisallowNull] School obj)
{
return obj.Name.GetHashCode();
}
}
위의 코드에서 School Class로 'IEqualityComparer'를 구현했다. 상속받은 Euqlas(), GetHashCode를 정의했다.
School[] schools = {
new School(){ Name = "school1", Address = "address1"},
new School(){ Name = "school2", Address = "address2"},
new School(){ Name = "school3", Address = "address3"},
new School(){ Name = "school4", Address = "address4"},
new School(){ Name = "school5", Address = "address5"},
new School(){ Name = "school3", Address = "address31"},
new School(){ Name = "school4", Address = "address41"},
};
IEnumerable<School> noduplicates = schools.Distinct(new CustomSchoolEqualityComparer());
foreach(School school in noduplicates)
{
Console.WriteLine($"name : {school.Name} / address : {school.Address}");
}
[Output]
name : school1 / address : address1
name : school2 / address : address2
name : school3 / address : address3
name : school4 / address : address4
name : school5 / address : address5
설명
name이 같은 School 객체는 첫 번째 값이 반환되어 school3, school4 의address 도 첫번째 값이 반환되고 있다.
Distinct<TSource>(IEnumerable<TSource>)
기본적으로 자주 사용되는 형식이며, 기본적으로 '같음' 비교자로 값을 비교하여 시퀀스에서 고유 요소를 반환한다.
예제
School[] schools = {
new School(){ Name = "school1", Address = "address1"},
new School(){ Name = "school2", Address = "address2"},
new School(){ Name = "school3", Address = "address3"},
new School(){ Name = "school4", Address = "address4"},
new School(){ Name = "school5", Address = "address5"},
new School(){ Name = "school3", Address = "address3"},
new School(){ Name = "school4", Address = "address4"},
new School(){ Name = "school3", Address = "address31"},
new School(){ Name = "school4", Address = "address41"},
};
IEnumerable<School> noduplicates = = schools.Distinct();
foreach (School school in noduplicates)
{
Console.WriteLine($"name : {school.Name} / address : {school.Address}");
}
[Output]
name : school1 / address : address1
name : school2 / address : address2
name : school3 / address : address3
name : school4 / address : address4
name : school5 / address : address5
name : school3 / address : address3
name : school4 / address : address4
name : school3 / address : address31
name : school4 / address : address41
기본적으로 'Distinct'는 참조형식으로 중복제거를 진행되기 때문에 속성의 값이 동일하다고 해도 참조(주소)가 다르기 때문에 해당 예제에서는 모든 값들이 나오는 게 정상이다.
만약 동일한 속성값이 중복되길 원한다면 'IEqualityComparer'에 정의해서 호출하거나 아래 DistinctBy()로 쉽게 해결이 가능하다.
DistinctBy()
정의
namespace : Systme.Linq
assembly : Systme.Linq.dll
시퀀스의 고유 요소 지정된 키에 의해 반환한다.
Overloads
DistinctBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>) | 지정된 키 선택기 함수에 따라 시퀀스에서 고유 요소를 반환합니다. |
DistinctBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>, IEqualityComparer<TKey>) | 지정된 키 선택기 함수에 따라 시퀀스에서 고유 요소를 반환하고 지정된 비교자를 사용하여 키를 비교합니다. |
❗비교값 반환 시 첫 번째 값이 반환된다.
⭐지연실행
DistinctBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>)
지정된 키 선택기 함수에 따라 시퀀스에서 고유 요소를 반환합니다.
public static System.Collections.Generic.IEnumerable<TSource> DistinctBy<TSource,TKey> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TKey> keySelector);
예제
School[] schools = {
new School(){ Name = "school1", Address = "address1"},
new School(){ Name = "school2", Address = "address2"},
new School(){ Name = "school3", Address = "address3"},
new School(){ Name = "school4", Address = "address4"},
new School(){ Name = "school5", Address = "address5"},
new School(){ Name = "school3", Address = "address3"},
new School(){ Name = "school4", Address = "address4"},
new School(){ Name = "school3", Address = "address31"},
new School(){ Name = "school4", Address = "address41"},
};
IEnumerable<School> noduplicates = schools.DistinctBy(x => x.Name);
foreach (School school in noduplicates)
{
Console.WriteLine($"name : {school.Name} / address : {school.Address}");
}
[Output]
name : school1 / address : address1
name : school2 / address : address2
name : school3 / address : address3
name : school4 / address : address4
name : school5 / address : address5
'Name'에 대해서 동일한 값이라면 'address'가 달라도 중복처리 된다. 중복이 되는 Key를 'Name' 속성으로 지정되어 있기 때문이다.
예제
IEnumerable<School> noduplicates = schools.DistinctBy(keySelector: x => (x.Name, x.Address)).ToList();
[Output]
name : school1 / address : address1
name : school2 / address : address2
name : school3 / address : address3
name : school4 / address : address4
name : school5 / address : address5
name : school3 / address : address31
name : school4 / address : address41
여러 속성에 대해서 중복처리 하고 싶다면 위의 코드처럼 괄호로 묶어 주면 된다.
DistinctBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>, IEqualityComparer<TKey>)
지정된 키 선택기 함수에 따라 시퀀스에서 고유 요소를 반환하고 지정된 비교자를 사용하여 키를 비교합니다.
public static System.Collections.Generic.IEnumerable<TSource> DistinctBy<TSource,TKey> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TKey> keySelector, System.Collections.Generic.IEqualityComparer<TKey>? comparer);
예제
public class CustomSchoolNameEqualityComparer : IEqualityComparer<string>
{
public bool Equals(string? x, string? y)
{
return string.Equals(x, y, StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode([DisallowNull] string obj)
{
return obj is null ? 0 : obj.ToLowerInvariant().GetHashCode();
}
}
School[] schools = {
new School(){ Name = "school1", Address = "address1"},
new School(){ Name = "school2", Address = "address2"},
new School(){ Name = "school3", Address = "address3"},
new School(){ Name = "school4", Address = "address4"},
new School(){ Name = "school5", Address = "address5"},
new School(){ Name = "SCHool3", Address = "address3"},
new School(){ Name = "schOOL4", Address = "address4"},
new School(){ Name = "SCHOOL3", Address = "address31"},
new School(){ Name = "school4", Address = "address41"},
};
IEnumerable<School> noduplicates = schools.DistinctBy(keySelector: x => x.Name, comparer: new CustomSchoolNameEqualityComparer());
foreach (School school in noduplicates)
{
Console.WriteLine($"name : {school.Name} / address : {school.Address}");
}
[Output]
name : school1 / address : address1
name : school2 / address : address2
name : school3 / address : address3
name : school4 / address : address4
name : school5 / address : address5
'IEqualityComparer' 상속받은 'CustomSchoolNameEqualityComparer'에 대소문자 구분 없이 비교 로직을 구성해 두었다.
복잡한 비교 로직이 있다면 ' IEqualityComparer' 상속받은 Class에 구성해서 사용하는 것이 좋을 것 같다.
'Programming > C# & .NET' 카테고리의 다른 글
[.NET] appsettings.json 추가하기 (0) | 2024.05.30 |
---|---|
[C#] Linq - Aggregate 메서드 (0) | 2023.06.27 |
[C#] LINQ 란? - 소개 (Language-Integrated Query) (1) | 2023.02.18 |
[C#] XmlElement 여러개 설정 (1) | 2023.01.11 |
[C#] XMl 직렬화, 역직렬화 Method 공유 (2) | 2023.01.06 |
댓글