LINQ: 不同的值

我从一个 XML 中得到了以下条目:

id           category


5            1
5            3
5            4
5            3
5            3

我需要这些东西的清单:

5            1
5            3
5            4

在 LINQ 中如何区分类别和 ID?

208340 次浏览

你是否试图在多个领域进行区分?如果是这样的话,只需使用匿名类型和 District 操作符就可以了:

var query = doc.Elements("whatever")
.Select(element => new {
id = (int) element.Attribute("id"),
category = (int) element.Attribute("cat") })
.Distinct();

如果您试图获得一组“较大”类型的独特值,但是只关注一些独特性方面的属性子集,那么您可能希望在 DistinctBy.cs中的 莫林克中实现 DistinctBy:

 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作为比较器,它将使用密钥类型的默认比较器。)

只需将 Distinct()与您自己的比较器一起使用。

Http://msdn.microsoft.com/en-us/library/bb338049.aspx

除了 Jon Skeet 的回答之外,您还可以使用表达式分组来得到每个组迭代的 w/a 计数中的唯一组:

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() };
// 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));
}

现在回答这个问题有点晚了,但是如果您想要整个元素,而不仅仅是您想要按以下值进行分组,那么您可能需要这样做:

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 很可能更快,但是如果性能不是问题,那么上面的解决方案将涉及更少的代码。

对于任何仍在寻找的人,这里有另一种实现自定义 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;
}
}

然后您可以创建一个扩展,它可以接受 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);

因为我们讨论的是每个元素只有一次,所以“集合”对我来说更有意义。

实现了类和 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()时考虑到了这一点