LINQ在特定屬性上的Distinct()

我正在使用LINQ進行學習,可是當我沒有簡單的列表時(我很容易作到簡單的整數列表,這不是問題),我沒法弄清楚如何使用Distinct。 若是要在對象的一個多個屬性的對象列表上使用Distinct ,該怎麼辦? web

示例:若是一個對象是Person ,具備Property Id 。 如何獲取全部Person並在其上使用Distinct和對象的屬性Id學習

Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"

我怎樣才能獲得Person1和Person3? 那可能嗎? 測試

若是LINQ沒法實現,那麼根據.NET 3.5中Person某些屬性來獲取Person列表的最佳方法是什麼? 網站


#1樓

如下代碼在功能上等同於Jon Skeet的答案this

在.NET 4.5上進行了測試,能夠在任何早期版本的LINQ上運行。 google

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
  this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
  HashSet<TKey> seenKeys = new HashSet<TKey>();
  return source.Where(element => seenKeys.Add(keySelector(element)));
}

偶然地, 在Google Code上查看Jon Skeet的DistinctBy.cs最新版本spa


#2樓

若是須要在多個屬性上使用Distinct方法,則能夠簽出個人PowerfulExtensions庫。 當前它還處於起步階段,可是您已經能夠在許多屬性上使用Distinct,Union,Intersect,Except等方法。 code

這是您的用法: 對象

using PowerfulExtensions.Linq;
...
var distinct = myArray.Distinct(x => x.A, x => x.B);

#3樓

與其餘.NET版本兼容的最佳方法是重寫Equals和GetHash來處理此問題(請參閱Stack Overflow問題。 此代碼返回不一樣的值。可是,我要返回的是強類型集合,而不是匿名類型 ),可是若是您須要在整個代碼中使用通用的東西,那麼本文中的解決方案很是有用。 blog


#4樓

當咱們在項目中面對這樣的任務時,咱們定義了一個小的API來構成比較器。

所以,用例是這樣的:

var wordComparer = KeyEqualityComparer.Null<Word>().
    ThenBy(item => item.Text).
    ThenBy(item => item.LangID);
...
source.Select(...).Distinct(wordComparer);

API自己以下所示:

using System;
using System.Collections;
using System.Collections.Generic;

public static class KeyEqualityComparer
{
    public static IEqualityComparer<T> Null<T>()
    {
        return null;
    }

    public static IEqualityComparer<T> EqualityComparerBy<T, K>(
        this IEnumerable<T> source,
        Func<T, K> keyFunc)
    {
        return new KeyEqualityComparer<T, K>(keyFunc);
    }

    public static KeyEqualityComparer<T, K> ThenBy<T, K>(
        this IEqualityComparer<T> equalityComparer,
        Func<T, K> keyFunc)
    {
        return new KeyEqualityComparer<T, K>(keyFunc, equalityComparer);
    }
}

public struct KeyEqualityComparer<T, K>: IEqualityComparer<T>
{
    public KeyEqualityComparer(
        Func<T, K> keyFunc,
        IEqualityComparer<T> equalityComparer = null)
    {
        KeyFunc = keyFunc;
        EqualityComparer = equalityComparer;
    }

    public bool Equals(T x, T y)
    {
        return ((EqualityComparer == null) || EqualityComparer.Equals(x, y)) &&
                EqualityComparer<K>.Default.Equals(KeyFunc(x), KeyFunc(y));
    }

    public int GetHashCode(T obj)
    {
        var hash = EqualityComparer<K>.Default.GetHashCode(KeyFunc(obj));

        if (EqualityComparer != null)
        {
            var hash2 = EqualityComparer.GetHashCode(obj);

            hash ^= (hash2 << 5) + hash2;
        }

        return hash;
    }

    public readonly Func<T, K> KeyFunc;
    public readonly IEqualityComparer<T> EqualityComparer;
}

更多詳細信息,請訪問咱們的網站: LINQ中的IEqualityComparer


#5樓

您可使用標準的Linq.ToLookup() 。 這將爲每一個惟一鍵建立一個值集合。 只需選擇集合中的第一項

Persons.ToLookup(p => p.Id).Select(coll => coll.First());
相關文章
相關標籤/搜索