Distinct()내 장 된 방법 으로 List 집합 에 대한 무 거 운 문제 에 대한 상세 한 설명

머리말
집합 에 대한 재 처리 라 고 하면 가장 먼저 생각 나 는 것 은 Linq 의 Distinct 확장 방식 입 니 다.일반적인 값 유형 에 대한 집합 은 재 처리 하기 쉽 습 니 다.직접 list.Distinct()를 사용 하면 됩 니 다.그러나 인용 유형의 집합 을 다시 하려 면(속성 값 이 같 으 면 중복 이 라 고 생각 합 니 다)직접 Distinct()는 안 됩 니 다.
먼저 팬 링크 List의 정 의 를 살 펴 보 겠 습 니 다.
public class List : IList, ICollection, IList, ICollection, IReadOnlyList, IReadOnlyCollection, IEnumerable, IEnumerable
이 를 통 해 알 수 있 듯 이 IEnumerable를 실 현 했 고 IEnumerable는 Distinct 방법 을 규정 했다.
이 방법 을 사용 할 때 주의해 야 한다.
(1)이 방법 은 원래 의 링크 를 바 꾸 지 않 는 다.
(2)이 방법 은 대상(dis 라 고 가정)을 되 돌려 줍 니 다.이 대상 을 통 해 원 링크 의 비 중복 요 소 를 매 거 할 수 있 지만 비 중복 요 소 를 새로운 대상 에 복사 하지 않 았 습 니 다(복사 도 하지 않 았 습 니 다)
(3)(2)dis 를 매 거 할 때 항상 기 존 링크 에 의존 하기 때문에 dis 를 얻 은 후에 기 존 링크 를 업데이트 하면 dis 매 거 진 을 사용 하면 기 존 링크 의 최신 상 태 를 사용 합 니 다.

 var list=new List<SampleVersionDto>()///          
때때로 Distinct()가 인용 형식 을 다시 사용 할 수 없 을 때 사용자 정의 코드 는 다음 과 같 습 니 다.

public class User
{
 public int Id { get; set; }
 public string Name { get; set; }
}

var list = new List<User>() 
{ 
 new User() { Id = 1, Name = "  " } ,
 new User() { Id = 1, Name = "  " } ,
 new User() { Id = 3, Name = "  " } ,
};

var newList1 = list.Distinct().ToList();
위 코드 를 실행 하면 원 하 는 결과 가 아니 라 new List 1 에 3 개의 요소 가 있 음 을 알 수 있 습 니 다.이러한 결과 가 발생 하 는 이 유 는 Distinct()가 기본 적 인 비교 기 를 사용 하여 값 을 비교 하여 시퀀스 의 비 중복 요 소 를 되 돌려 주기 때 문 입 니 다.값 유형 에 대해 서 는 기본 적 인 상등 비교 기 가 비교 값 이 같 는 지,인용 유형 에 대해 서 는 기본 적 인 상등 비교 기 가 비교 대상 의 참조 주소 이기 때문에 상기 예 에서 속성 값 이 같 더 라 도 무 게 를 줄 수 없습니다.
IEqualityComparer
똑똑 한 우 리 는 Linq 가 우 리 를 위해 무 거 운 방법 을 다시 실 어 주 었 고 우리 의 수 요 를 만족 시 킬 수 있다 는 것 을 쉽게 알 수 있다.

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer);
다시 불 러 오 는 이 방법 은 IEquality Comparercomparer 인 자 를 하나 더 제공 합 니 다.일반적인 인터페이스 입 니 다.우 리 는 이 인 터 페 이 스 를 실현 하기 만 하면 우리 의 무 거 운 수 요 를 만족 시 킬 수 있 습 니 다.

public class UserComparer : IEqualityComparer<User>
{
 public bool Equals(User x, User y)
 {
 return x.Id == y.Id && x.Name == y.Name;
 }

 public int GetHashCode(User obj)
 {
 return obj.ToString().GetHashCode();
 }
}
IEquality Comparer는 두 가지 방법 을 정 의 했 습 니 다.하 나 는 Equals 이 고 하 나 는 GetHash Code 입 니 다.여기 서 참고 자 료 를 찾 아 보 니 비 교 를 할 때 기본적으로 GetHashCode 를 통 해 두 요 소 를 비교 하고 HashCode 가 다 르 면 두 요소 가 다르다 고 생각 하고 같 으 면 Equals 방법 으로 비교 합 니 다.그래서 여기 서 사용자 대상 GetHashCode 를 직접 처리 할 수 없고 문자열 로 변환 한 다음 GetHashCode 를 사용 합 니 다.이 무 거 운 적재 방법 을 통 해 우 리 는 목적 에 도달 할 수 있다.

ar newList2 = list.Distinct(new UserComparer()).ToList();
심지어 우 리 는 특정한 속성 이 같 으 면 중복 된다 고 생각 하 는 효 과 를 실현 할 수 있다.Equals 방법 에서 비교 하고 자 하 는 방식 으로 처리 하면 된다.
사 고 를 연장 하 다.
Distinct 의 리 셋 방법 은 기본적으로 우리 의 다양한 리 셋 수 요 를 만족 시 킬 수 있 습 니 다.그러나 가 고 싶 어도 어색 합 니 다.바로 비슷 한 리 셋 수요 가 있다 면 우 리 는 IEquality Comparer인 터 페 이 스 를 실현 하 는 유형 을 추가 해 야 합 니 다.유연성 이 부족 하고 패 키 징 재 활용 의 원칙 에 따라 이 방면 에서 최적화 할 수 있 을 지 생각 했 습 니 다.공교롭게도 최근 에 안 드 로 이 드 프로젝트 를 만 들 고 자 바 를 배 웠 습 니 다.자 바 는 익명 으로 인 터 페 이 스 를 실현 하 는 문법 적 특성 이 있다 는 것 을 알 게 되 었 습 니 다.만약 에 C\#도 익명 으로 인 터 페 이 스 를 실현 할 수 있다 면 그렇게 많은 종 류 를 추가 해서 인 터 페 이 스 를 실현 할 필요 가 없습니다.안 타 깝 게 도 C\#에 이런 특성 이 없습니다.자 료 를 보 니 자바 도 진정한 의미 의 익명 실현 이 아니 라 컴 파일 러 가 손발 을 만 들 었 고 컴 파일 할 때 진실 한 종 류 를 만들어 인 터 페 이 스 를 실현 하 는 것 이 라 고 생각 합 니 다.자 료 를 찾 은 후에 마침내 좋 은 해결 방안 을 찾 았 다.

public class LambdaComparer<T> : IEqualityComparer<T>
{
 private readonly Func<T, T, bool> _lambdaComparer;
 private readonly Func<T, int> _lambdaHash;
 public LambdaComparer(Func<T, T, bool> lambdaComparer)
 : this(lambdaComparer, EqualityComparer<T>.Default.GetHashCode)
 {
 }
 public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
 {
 if (lambdaComparer == null)
  throw new ArgumentNullException("lambdaComparer");
 if (lambdaHash == null)
  throw new ArgumentNullException("lambdaHash");
  _lambdaComparer = lambdaComparer;
  _lambdaHash = lambdaHash;
 }

 public bool Equals(T x, T y)
 {
 return _lambdaComparer(x, y);
 }

 public int GetHashCode(T obj)
 {
 return _lambdaHash(obj);
 }
}
교묘 하 게 범 형 의뢰 방식 을 채택 하여 IEquality Comparer인터페이스,Equals,GetHash Code 의 실현 을 정의 하고 들 어 오 는 의뢰 방법 에 의 해 결정 되 며 그 다음은 간단 합 니 다.

var newList3 = list.Distinct(new LambdaComparer<User>((a, b) => a.Id == b.Id && a.Name == b.Name, obj => obj.ToString().GetHashCode())).ToList();
익숙 한 표기 법 이 아 닙 니까?비교 하고 싶 은 대로 비교 하고 편리 하 며 빠 릅 니 다.그렇게 많은 종 류 를 정의 하여 인 터 페 이 스 를 실현 하고 목적 을 달성 할 필요 가 없습니다.Linq 에는 IEquality Comparer인 터 페 이 스 를 사용 하 는 확장 방법 이 많 습 니 다.이런 방식 을 통 해 중 용 률 을 크게 높 일 수 있다
참고 자료
1、 https://www.jb51.net/article/162602.htm
2、https://ask.helplib.com/c-Sharp/post_1277383
총결산
이상 은 이 글 의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기