我从XML中设置了以下项目:
id category
5 1
5 3
5 4
5 3
5 3
我需要这些项目的明确列表:
5 1
5 3
5 4
如何在LINQ中区分Category AND Id?
答案 0 :(得分:208)
您是否尝试通过多个字段区分?如果是这样,只需使用匿名类型和Distinct运算符,它应该没问题:
var query = doc.Elements("whatever")
.Select(element => new {
id = (int) element.Attribute("id"),
category = (int) element.Attribute("cat") })
.Distinct();
如果您尝试获取“较大”类型的一组不同值,但只查看不同方面的某些属性子集,则可能需要在{{3}中实现DistinctBy
} MoreLINQ:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector,
IEqualityComparer<TKey> comparer)
{
HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
foreach (TSource element in source)
{
if (knownKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
(如果你传入null
作为比较器,它将使用密钥类型的默认比较器。)
答案 1 :(得分:32)
只需将Distinct()
与您自己的比较器一起使用。
答案 2 :(得分:24)
除了Jon Skeet的回答之外,您还可以使用group by表达式来获取每个组迭代的唯一组和计数:
var query = from e in doc.Elements("whatever")
group e by new { id = e.Key, val = e.Value } into g
select new { id = g.Key.id, val = g.Key.val, count = g.Count() };
答案 3 :(得分:12)
对于任何仍在寻找的人;这是实现自定义lambda比较器的另一种方法。
public class LambdaComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, T, bool> _expression;
public LambdaComparer(Func<T, T, bool> lambda)
{
_expression = lambda;
}
public bool Equals(T x, T y)
{
return _expression(x, y);
}
public int GetHashCode(T obj)
{
/*
If you just return 0 for the hash the Equals comparer will kick in.
The underlying evaluation checks the hash and then short circuits the evaluation if it is false.
Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects),
you will always fall through to the Equals check which is what we are always going for.
*/
return 0;
}
}
然后你可以为linq Distinct创建一个可以接受lambda的
的扩展 public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, T, bool> lambda)
{
return list.Distinct(new LambdaComparer<T>(lambda));
}
<强>用法:强>
var availableItems = list.Distinct((p, p1) => p.Id== p1.Id);
答案 4 :(得分:8)
我的答案有点迟了,但如果您想要整个元素,而不仅仅是想要分组的值,您可能想要这样做:
var query = doc.Elements("whatever")
.GroupBy(element => new {
id = (int) element.Attribute("id"),
category = (int) element.Attribute("cat") })
.Select(e => e.First());
这将通过选择为您提供与您的组匹配的第一个整个元素,就像Jon Skeets使用DistinctBy的第二个示例,但没有实现IEqualityComparer比较器。 DistinctBy很可能会更快,但如果性能不是问题,上面的解决方案将涉及更少的代码。
答案 5 :(得分:4)
// First Get DataTable as dt
// DataRowComparer Compare columns numbers in each row & data in each row
IEnumerable<DataRow> Distinct = dt.AsEnumerable().Distinct(DataRowComparer.Default);
foreach (DataRow row in Distinct)
{
Console.WriteLine("{0,-15} {1,-15}",
row.Field<int>(0),
row.Field<string>(1));
}
答案 6 :(得分:0)
由于我们正在谈论将每个元素都精确地设置一次,所以“设置”对我来说更有意义。
已实现类和IEqualityComparer的示例:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Product(int x, string y)
{
Id = x;
Name = y;
}
}
public class ProductCompare : IEqualityComparer<Product>
{
public bool Equals(Product x, Product y)
{ //Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.Id == y.Id && x.Name == y.Name;
}
public int GetHashCode(Product product)
{
//Check whether the object is null
if (Object.ReferenceEquals(product, null)) return 0;
//Get hash code for the Name field if it is not null.
int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();
//Get hash code for the Code field.
int hashProductCode = product.Id.GetHashCode();
//Calculate the hash code for the product.
return hashProductName ^ hashProductCode;
}
}
现在
List<Product> originalList = new List<Product> {new Product(1, "ad"), new Product(1, "ad")};
var setList = new HashSet<Product>(originalList, new ProductCompare()).ToList();
setList
将具有唯一元素
我在处理.Except()
并返回设定差的过程中想到了这一点