람다와 구별 되는가? c1.CustomerId == c2.CustomerId); 그러한 확장이

그렇습니다. 나는 열거 할 수 있고 명확한 가치를 얻고 싶습니다.

를 사용하면 System.Linq물론이라는 확장 방법이 Distinct있습니다. 간단한 경우 다음과 같이 매개 변수없이 사용할 수 있습니다.

var distinctValues = myStringList.Distinct();

좋고 훌륭하지만 동등성을 지정 해야하는 열거 가능한 객체가있는 경우 사용 가능한 유일한 과부하는 다음과 같습니다.

var distinctValues = myCustomerList.Distinct(someEqualityComparer);

항등 비교 자 인수는의 인스턴스 여야합니다 IEqualityComparer<T>. 물론이 작업을 수행 할 수는 있지만 다소 장황하고 음탕합니다.

내가 기대했던 것은 람다가 걸리는 과부하입니다 .Func <T, T, bool> :

var distinctValues
    = myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);

그러한 확장이 있는지 또는 동등한 해결 방법이 있는지 아는 사람이 있습니까? 아니면 뭔가 빠졌습니까?

또는 IEqualityComparer 인라인을 지정하는 방법이 있습니까?

최신 정보

Anders Hejlsberg 가이 주제에 대한 MSDN 포럼 의 게시물 에 대한 답변을 찾았습니다 . 그는 말한다 :

두 객체가 동일하게 비교 될 때 동일한 GetHashCode 반환 값을 가져야합니다. 그렇지 않으면 Distinct에서 내부적으로 사용되는 해시 테이블이 올바르게 작동하지 않습니다. IEqualityComparer는 Equals 및 GetHashCode의 호환 가능한 구현을 단일 인터페이스로 패키지하기 때문에 IEqualityComparer를 사용합니다.

나는 그것이 의미가 있다고 생각합니다 ..



답변

IEnumerable<Customer> filteredList = originalList
  .GroupBy(customer => customer.CustomerId)
  .Select(group => group.First());

답변

MoreLINQDistinctBy 에서 원하는 것처럼 보입니다 . 그런 다음 쓸 수 있습니다 :

var distinctValues = myCustomerList.DistinctBy(c => c.CustomerId);

다음은 컷 다운 버전입니다 DistinctBy(무효 검사 및 자체 키 비교기를 지정할 수있는 옵션 없음).

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
     (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> knownKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (knownKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

답변

물건을 마무리합니다 . 나는 여기에 온 대부분의 사람들이 라이브러리를 사용하지 않고 가능한 최고의 성능으로 가능한 가장 간단한 솔루션을 원한다고 생각합니다 .

(나를 위해 방법으로 허용 된 그룹은 성능 측면에서 과잉이라고 생각합니다.)

다음은 null 값에도 작동 하는 IEqualityComparer 인터페이스를 사용하는 간단한 확장 방법 입니다.

용법:

var filtered = taskList.DistinctBy(t => t.TaskExternalId).ToArray();

확장 방법 코드

public static class LinqExtensions
{
    public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property)
    {
        GeneralPropertyComparer<T, TKey> comparer = new GeneralPropertyComparer<T,TKey>(property);
        return items.Distinct(comparer);
    }
}
public class GeneralPropertyComparer<T,TKey> : IEqualityComparer<T>
{
    private Func<T, TKey> expr { get; set; }
    public GeneralPropertyComparer (Func<T, TKey> expr)
    {
        this.expr = expr;
    }
    public bool Equals(T left, T right)
    {
        var leftProp = expr.Invoke(left);
        var rightProp = expr.Invoke(right);
        if (leftProp == null && rightProp == null)
            return true;
        else if (leftProp == null ^ rightProp == null)
            return false;
        else
            return leftProp.Equals(rightProp);
    }
    public int GetHashCode(T obj)
    {
        var prop = expr.Invoke(obj);
        return (prop==null)? 0:prop.GetHashCode();
    }
}

답변

이와 같은 확장 방법 과부하는 없습니다. 나는 과거에 이것이 좌절감을 느꼈고 일반적 으로이 문제를 다루는 도우미 클래스를 작성합니다. 목표는를로 변환하는 Func<T,T,bool>IEqualityComparer<T,T>입니다.

public class EqualityFactory {
  private sealed class Impl<T> : IEqualityComparer<T,T> {
    private Func<T,T,bool> m_del;
    private IEqualityComparer<T> m_comp;
    public Impl(Func<T,T,bool> del) {
      m_del = del;
      m_comp = EqualityComparer<T>.Default;
    }
    public bool Equals(T left, T right) {
      return m_del(left, right);
    }
    public int GetHashCode(T value) {
      return m_comp.GetHashCode(value);
    }
  }
  public static IEqualityComparer<T,T> Create<T>(Func<T,T,bool> del) {
    return new Impl<T>(del);
  }
}

이것은 당신이 다음을 쓸 수 있습니다

var distinctValues = myCustomerList
  .Distinct(EqualityFactory.Create((c1, c2) => c1.CustomerId == c2.CustomerId));

답변

속기 솔루션

myCustomerList.GroupBy(c => c.CustomerId, (key, c) => c.FirstOrDefault());

답변

이것은 당신이 원하는 것을 할 것이지만 성능에 대해서는 모르겠습니다.

var distinctValues =
    from cust in myCustomerList
    group cust by cust.CustomerId
    into gcust
    select gcust.First();

적어도 장황하지 않습니다.


답변

다음은 필요한 것을 수행하는 간단한 확장 방법입니다.

public static class EnumerableExtensions
{
    public static IEnumerable<TKey> Distinct<T, TKey>(this IEnumerable<T> source, Func<T, TKey> selector)
    {
        return source.GroupBy(selector).Select(x => x.Key);
    }
}

그들이 이와 같은 독특한 방법을 프레임 워크에 굽지 않은 것은 부끄러운 일입니다.