我有一個C#中的對象列表。所有的對象都包含屬性dept和course。
有幾個對象具有相同的部門和課程。從列表中刪除具有重複屬性的對象
如何修剪列表(或創建新列表),其中每個唯一的對象(部分&當然)屬性只有一個對象。
[任何額外的副本都跌出名單]
我知道如何與一個單一的屬性來完成這個:
fooList.GroupBy(x => x.dept).Select(x => x.First());
不過,我想知道如何爲多個屬性做到這一點( 2或更多)?
我有一個C#中的對象列表。所有的對象都包含屬性dept和course。
有幾個對象具有相同的部門和課程。從列表中刪除具有重複屬性的對象
如何修剪列表(或創建新列表),其中每個唯一的對象(部分&當然)屬性只有一個對象。
[任何額外的副本都跌出名單]
我知道如何與一個單一的屬性來完成這個:
fooList.GroupBy(x => x.dept).Select(x => x.First());
不過,我想知道如何爲多個屬性做到這一點( 2或更多)?
要使用多個屬性,你可以使用匿名類型:
var query = fooList.GroupBy(x => new { x.Dept, x.Course })
.Select(x => x.First());
當然,這要看是什麼類型的Dept
和Course
是確定的平等。或者,您的課程可以實施IEqualityComparer<T>
,然後您可以使用接受比較器的Enumerable.Distinct
method。
另一種方法是用IEqualityComparer<Foo>
一起使用LINQ Distinct
擴展方法。它要求你實現一個比較器;然而,後者是可重用和可測試的。
public class FooDeptCourseEqualityComparer : IEqualityComparer<Foo>
{
public bool Equals(Foo x, Foo y)
{
return
x.Dept == y.Dept &&
x.Course.ToLower() == y.Course.ToLower();
}
public int GetHashCode(Foo obj)
{
unchecked {
return 527 + obj.Dept.GetHashCode() * 31 + obj.Course.GetHashCode();
}
}
#region Singleton Pattern
public static readonly FooDeptCourseEqualityComparer Instance =
new FooDeptCourseEqualityComparer();
private FooDeptCourseEqualityComparer() { }
#endregion
}
我的例子使用單例模式。由於該類沒有任何狀態信息,因此每次我們使用它時都不需要創建新的實例。
我的代碼不處理null
值。當然,如果可能發生,你將不得不處理它們。
獨特的值返回這樣
var result = fooList.Distinct(FooDeptCourseEqualityComparer.Instance);
UPDATE
我建議使用接受lambda表達式在構造函數中,可以在多個場合重複使用一個通用的EqualityComparer類
public class LambdaEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _areEqual;
private Func<T, int> _getHashCode;
public LambdaEqualityComparer(Func<T, T, bool> areEqual,
Func<T, int> getHashCode)
{
_areEqual = areEqual;
_getHashCode = getHashCode;
}
public LambdaEqualityComparer(Func<T, T, bool> areEqual)
: this(areEqual, obj => obj.GetHashCode())
{
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
return _areEqual(x, y);
}
public int GetHashCode(T obj)
{
return _getHashCode(obj);
}
#endregion
}
您可以使用它像這樣
var comparer = new LambdaEqualityComparer<Foo>(
(x, y) => x.Dept == y.Dept && x.Course == y.Course,
obj => {
unchecked {
return 527 + obj.Dept.GetHashCode() * 31 + obj.Course.GetHashCode();
}
}
);
var result = fooList.Distinct(comparer);
注意:必須提供的哈希碼的計算,因爲Distinct
使用內部Set<T>
類,後者又使用散列碼。
更新#2
甚至更通用的相等比較器自動執行所述比較和接受屬性訪問的列表;但是,您無法控制比較的執行方式。
public class AutoEqualityComparer<T> : IEqualityComparer<T>
{
private Func<T, object>[] _propertyAccessors;
public AutoEqualityComparer(params Func<T, object>[] propertyAccessors)
{
_propertyAccessors = propertyAccessors;
}
#region IEqualityComparer<T> Members
public bool Equals(T x, T y)
{
foreach (var getProp in _propertyAccessors) {
if (!getProp(x).Equals(getProp(y))) {
return false;
}
}
return true;
}
public int GetHashCode(T obj)
{
unchecked {
int hash = 17;
foreach (var getProp in _propertyAccessors) {
hash = hash * 31 + getProp(obj).GetHashCode();
}
return hash;
}
}
#endregion
}
使用
var comparer = new AutoEqualityComparer<Foo>(foo => foo.Dept,
foo => foo.Course);
var result = fooList.Distinct(comparer);
請問您的列表需要可排序? – 2012-04-17 13:39:15
我到達這一點時已經對列表進行了排序。 – Baxter 2012-04-17 13:41:54