首页 > 解决方案 > c# 根据属性从类列表中选择实例

问题描述

鉴于以下类结构需要根据自定义属性值提取各种成员:

class Item{

    public Item(int position, Image image)
    {
        Position = position;
        Image = image;
    }

    public int Position { get; set; }
    public Image Image { get; set; }
    public int Quality { get; set; }
}

class Items : List<Item> {}
class ConsolidatedItems : List<Items> {}

如何获得基于位置加入的质量的“最佳”项目列表(换句话说,位置相同的组项目):

输入

Items1:

Item1: 1, ImageBinary, 100
Item2: 2, ImageBinary, 98
Item3: 3, ImageBinary, 45
Item4: 4, ImageBinary, 66

Items2:
Item1: 1, ImageBinary, 76
Item2: 2, ImageBinary, 80
Item4: 4, ImageBinary, 33

Items3:
Item1: 2, ImageBinary, 76
Item2: 3, ImageBinary, 80
Item4: 4, ImageBinary, 90

输出

BestItems:
Item1: 1, ImageBinary, 100 (from Items1)
Item2: 2, ImageBinary, 98 (from Items1)
Item3: 3, ImageBinary, 80 (from Items3)
Item4: 4, ImageBinary, 90 (from Items4)

标签: c#.netlist

解决方案


LINQ

var best = data
    .GroupBy(x => x.Position)
    .Select(x => x.Aggregate(
        (result, item) => item.Quality > result.Quality ? item : result)
    );
  • 假设这data是一个集合Item
  • 确保添加using System.Linq;
  • best如果IEnumerable您希望使用,您可以将其转换为列表或数组,ToList()或者ToArray()

根据讨论进行编辑:如果您data是 的实例ConsolidatedItems,即嵌套集合,则需要先使用以下方法将其展平SelectMany

var best = data
    .SelectMany(x => x)
    .GroupBy(x => x.Position)
    .Select(x => x.Aggregate(
        (result, item) => item.Quality > result.Quality ? item : result)
    );

细节

  1. data包含您的条目
  2. GroupBy创建一个集合,该集合key是您选择用于分组的属性或计算值。您当然可以遍历其所有项目,这些项目将在接下来的步骤中派上用场。
  3. Select将为每个组计算一个新实体——质量最好的那个。
  4. Aggregate可能是这里最困难的功能。它遍历组的成员并保留一个元素作为结果。结果用第一个元素初始化。然后Aggregate继续遍历整个集合并将每个项目与当前最佳结果进行比较。最后,它返回具有最佳元素的结果。

最佳实践

请注意,您的集合类设计得不好。看看这里为什么不继承表单 List


推荐阅读