所以,假设我有如下内容:
public class Element
{
public int ID;
public int Type;
public Properties prorerty;
...
}
and
public class Properties
{
public int Id;
public string Property;
...
}
我有一个清单:
List Elements = new List();
在Element类的property列中获得所有不同值的列表的最干净的方法是什么?我的意思是,我可以在列表中迭代,并将所有不重复的值添加到另一个字符串列表中,但这似乎既肮脏又低效。我有一种感觉,有一些神奇的林克结构可以在一行中做到这一点,但我还没能想出任何东西。
var results = Elements.Distinct();
注意:您必须覆盖.Equals
和.GetHashCode()
public class Element : IEqualityComparer<Element>
{
public bool Equals(Element x, Element y)
{
if (x.ID == y.ID)
{
return true;
}
else
{
return false;
}
}
}
public int GetHashCode(Element obj)
{
return obj.ID.GetHashCode();
}
使用下面显示的方法之一不是更简单吗:)?您可以通过一些键对域对象进行分组,然后选择FirstOrDefault,如下所示。这是我对类似问题的回答的副本:获取唯一值-原始答案
更有趣的选择是创建一些Comparer适配器,该适配器将带您域对象,并创建Comparer可以开箱即用/使用的其他对象。基于比较器,您可以创建自定义linq扩展,如下面的示例所示。希望有帮助:)
[TestMethod]
public void CustomDistinctTest()
{
// Generate some sample of domain objects
var listOfDomainObjects = Enumerable
.Range(10, 10)
.SelectMany(x =>
Enumerable
.Range(15, 10)
.Select(y => new SomeClass { SomeText = x.ToString(), SomeInt = x + y }))
.ToList();
var uniqueStringsByUsingGroupBy = listOfDomainObjects
.GroupBy(x => x.SomeText)
.Select(x => x.FirstOrDefault())
.ToList();
var uniqueStringsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeText).ToList();
var uniqueIntsByCustomExtension = listOfDomainObjects.DistinctBy(x => x.SomeInt).ToList();
var uniqueStrings = listOfDomainObjects
.Distinct(new EqualityComparerAdapter<SomeClass, string>(x => x.SomeText))
.OrderBy(x=>x.SomeText)
.ToList();
var uniqueInts = listOfDomainObjects
.Distinct(new EqualityComparerAdapter<SomeClass, int>(x => x.SomeInt))
.OrderBy(x => x.SomeInt)
.ToList();
}
自定义比较器适配器:
public class EqualityComparerAdapter<T, V> : EqualityComparer<T>
where V : IEquatable<V>
{
private Func<T, V> _valueAdapter;
public EqualityComparerAdapter(Func<T, V> valueAdapter)
{
_valueAdapter = valueAdapter;
}
public override bool Equals(T x, T y)
{
return _valueAdapter(x).Equals(_valueAdapter(y));
}
public override int GetHashCode(T obj)
{
return _valueAdapter(obj).GetHashCode();
}
}
自定义linq扩展(DistinctBy扩展方法的定义):
// Embed this class in some specific custom namespace
public static class DistByExt
{
public static IEnumerable<T> DistinctBy<T,V>(this IEnumerable<T> enumerator,Func<T,V> valueAdapter)
where V : IEquatable<V>
{
return enumerator.Distinct(new EqualityComparerAdapter<T, V>(valueAdapter));
}
}
测试用例中使用的域类的定义:
public class SomeClass
{
public string SomeText { get; set; }
public int SomeInt { get; set; }
}
var props = Elements.Select(x => x.Properties).Distinct();
并确保覆盖了.Equals()
和.GetHashCode()
方法
或者,如果您需要来自Properties
:的直接字符串
var props = Elements
.Select(x => x.Properties != null ? x.Properties.Property : null)
.Distinct();
如果您需要Properties
字段上的字符串字段,并且如果您知道Properties
字段prorerty
从来都不是null
,只需使用
IEnumerable<string> uniqueStrings = Elements
.Select(e => e.prorerty.Property).Distinct();
如果prorerty
有可能为null,请在lambda中处理这种情况。
这将使用String
的默认相等比较器,这是一个独立于区域性和区分大小写的序号比较。
LINQPad(C#程序)的工作示例
void Main()
{
var ret = new List<Element>();
ret.Add(new Element(){ID=1});
ret.Add(new Element(){ID=1});
ret.Add(new Element(){ID=2});
ret = ret.GroupBy(x=>x.ID).Select(x=>x.First()).ToList();
Console.WriteLine(ret.Count()); // shows 2
}
public class Element
{
public int ID;
public int Type;
public Properties prorerty;
}
public class Properties
{
public int Id;
public string Property;
}