代码之家  ›  专栏  ›  技术社区  ›  balint

Linq:不同的值

  •  125
  • balint  · 技术社区  · 15 年前

    我从XML中设置了以下项:

    id           category
    
    5            1
    5            3
    5            4
    5            3
    5            3
    

    我需要这些项目的独特列表:

    5            1
    5            3
    5            4
    

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

    7 回复  |  直到 6 年前
        1
  •  201
  •   feelingsofwhite Jon Skeet    8 年前

    您是否试图通过多个字段来区分?如果是这样,只需使用匿名类型和distinct运算符就可以了:

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

    如果您试图获得“更大”类型的一组不同的值,但只查看属性的某些子集以获得显著性方面,那么您可能需要 DistinctBy 执行于 MoreLINQ 在里面 DistinctBy.cs :

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

        2
  •  31
  •   Stu    11 年前

    只使用 Distinct() 用你自己的比较器。

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

        3
  •  24
  •   James Alexander    15 年前

    除了jon skeet的答案之外,您还可以使用group by表达式为每个组迭代获取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() };
    
        4
  •  12
  •   Ricky Gummadi    9 年前

    对于仍在查找的任何一个;这里是实现自定义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的linq distinct创建扩展

       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);
    
        5
  •  8
  •   Olle Johansson    10 年前

    我的回答有点晚了,但是如果您想要整个元素,而不仅仅是要分组的值,您可能需要这样做:

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

    这将为您提供按选择匹配组的第一个完整元素,类似于使用distinctby的jon skeets第二个示例,但没有实现iequalityComparer比较器。Distributby很可能更快,但是如果性能不是问题,上面的解决方案将涉及更少的代码。

        6
  •  3
  •   Omar Ali    12 年前
    // 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)); 
    }
    
        7
  •  0
  •   Aditya A V S    6 年前

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

    实现类和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() 返回设定差