繁体   English   中英

LINQ不同或按多个属性分组

[英]linq distinct or group by multiple properties

如何使用c#和Linq从下一个列表中获取result

 var pr = new List<Product>()
   {
       new Product() {Title="Boots",Color="Red",    Price=1},
       new Product() {Title="Boots",Color="Green",  Price=1},
       new Product() {Title="Boots",Color="Black",  Price=2},

       new Product() {Title="Sword",Color="Gray", Price=2},
       new Product() {Title="Sword",Color="Green",Price=2}
   };

Result

        {Title="Boots",Color="Red",  Price=1},               
        {Title="Boots",Color="Black",  Price=2},             
        {Title="Sword",Color="Gray", Price=2}

我知道我应该使用GroupByDistinct ,但是了解如何获得所需的东西

   List<Product> result = pr.GroupBy(g => g.Title, g.Price).ToList(); //not working
   List<Product> result  = pr.Distinct(...);

请帮忙

按所需属性分组,然后选择:

List<Product> result = pr.GroupBy(g => new { g.Title, g.Price })
                         .Select(g => g.First())
                         .ToList();

虽然可以使用新的匿名类型,但在方法之外创建自己的类型或使用Tuple可能更有意义,更具可读性和可使用性。 (有时,使用分隔的字符串可能就足够了: string.Format({0}.{1}, g.Title, g.Price)

List<Product> result = pr.GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
                     .ToList();

List<Product> result = pr.GroupBy(g => new ProductTitlePriceGroupKey(g.Title, g.Price))
                     .ToList();

至于获得所需的结果集,提供的答案建议只返回第一个,也许就您的目的而言还可以,但是理想情况下,您需要提供一种聚合或忽略Color方法。

例如,也许您宁愿以某种方式列出其中包含的颜色:

List<Product> result = pr
                     .GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
                     .Select(x => new Product()
                             { 
                                  Title = x.Key.Item1, 
                                  Price = x.Key.Item2,
                                  Color = string.Join(", ", x.Value.Select(y => y.Color) // "Red, Green"
                             })
                     .ToList();

对于颜色的简单字符串属性,将它们简单地串联起来可能很有意义。 如果您在那里有另一个实体,或者只是不想抽象出该信息,那么最好最好是完全拥有另一个具有该实体类型集合的实体。 例如,如果您要按标题和颜色分组,则可能需要显示平均价格或价格范围,而仅选择每个组中的第一个将阻止您这样做。

List<ProductGroup> result = pr
                     .GroupBy(g => new Tuple<string, decimal>(g.Title, g.Price))
                     .Select(x => new ProductGroup()
                             { 
                                  Title = x.Key.Item1, 
                                  Price = x.Key.Item2,
                                  Colors = x.Value.Select(y => y.Color)
                             })
                     .ToList();

如果要将某些逻辑抽象为可重用的扩展方法,则可以添加以下内容:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (!seenKeys.Contains(keySelector(element)))
        {
            seenKeys.Add(keySelector(element));
            yield return element;
        }
    }
}

这将适用于单个属性和复合属性,并返回第一个匹配的元素

// distinct by single property
var productsByTitle = animals.DistinctBy(a => a.Title);

// distinct by multiple properties
var productsByTitleAndColor = animals.DistinctBy(a => new { a.Title, a.Color} );

这种方法的一个好处(而不是先按+分组)是可以返回一个可枚举的可枚举数,以防万一您有后来的标准而不强迫您遍历整个集合

进一步阅读linq查询可从对象列表中返回不同的字段值

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM