如何根据常见的 属性 过滤列表(只有这样才能找到最小值)

How to filter a list based on a common property (only then to find the min value)

问题描述:

我有一个 Manufacturers 列表的场景,每个列表包含一个 IdCapacityCodePrice。我想找到最便宜的价格,但仅限于所有制造商具有相同 CapacityCode 共同点的商品。

public class Manufacturer
{ 
    public int Id { get; set; } 
    public string CapacityCode { get; set; }
    public decimal Price { get; set; }
}

我的目标:

根据具有相同容量代码的项目过滤列表,然后找到最低价格。

例如:

{
    "Manufacturers": [
    {
        "Id": 1,
        "CapacityCode": "Foo",
        "Price": 15
    },
    {
        "Id": 1,
        "CapacityCode": "Boo", // Manufacture 2 has no "Boo" so it should be filtered
        "Price": 10
    },
    {
        "Id": 2,
        "CapacityCode": "Foo",
        "Price": 30
    },
    {
        "Id": 2,
        "CapacityCode": "Zoo", // Manufacture 1 has no "Zoo" so it should be filtered
        "Price": 20
    }
}

筛选列表的输出应为:

{
    {
        "Id": 1,
        "CapacityCode": "Foo",
        "Price": 15
    },
    {
        "Id": 2,
        "CapacityCode": "Foo",
        "Price": 30
    }
}

所以最低价格应该是 15。

我试过了(而且有效):

var groups = source.Manufacturers
    .GroupBy(m => m.CapacityCode)
    .ToList();

var max = groups.Max(g => g.Count());
var filtered = new List<Manufacturer>();

foreach (var group in groups)
{
    if (group.Count() != max)
        continue;

    filtered.AddRange(group);
}

decimal minPrice = filtered.Min(m => m.Price);

我的问题:

如何在性能和可读性方面达到相同的结果?

IIUC 你的问题,没有必要对 Manufacturer 列表进行两次分组。您可以按 CapacityCode 对其进行分组并找到最大计数。然后按最大数量过滤组并使用 SelectMany 展平项目,按 Price 排序,最后获得最低价格,如果需要的话

var groups = manufacturers
    .GroupBy(m => m.CapacityCode)
    .ToList();

var count = groups.Max(g => g.Count());

var result = groups
    .Where(g => g.Count() == count)
    .SelectMany(g => g)
    .OrderBy(m => m.Price)
    .ToList();

var minPrice = result.FirstOrDefault()?.Price ?? 0;

您可以按 CapacityCodeToLookup, get the max count with Max, filter groups with the max count with Where, flatten the groups into IEnumerable<Manufacturer> with SelectMany, and sort the prices with OrderBy 对制造商进行分组。

var manufacturers = new List<Manufacturer> {
    new Manufacturer
    {
        Id = 1,
        CapacityCode = "Foo",
        Price = 15
    },
    new Manufacturer
    {
        Id = 1,
        CapacityCode = "Boo",
        Price = 10
    },
    new Manufacturer
    {
        Id = 2,
        CapacityCode = "Foo",
        Price = 30
    } 
    new Manufacturer
    {
        Id = 2,
        CapacityCode = "Zoo",
        Price = 20
    },
};

var groups = manufacturers.ToLookup(manufacturer => manufacturer.CapacityCode);

var maxCount = groups.Max(group => group.Count());

var result = groups
    .Where(group => group.Count() == maxCount)
    .SelectMany(group => group)
    .OrderBy(manufacturer => manufacturer.Price)
    .ToList();