Как отфильтровать список на основе общего свойства (только тогда, чтобы найти минимальное значение) - PullRequest
0 голосов
/ 29 апреля 2020

Описание проблемы:

У меня есть сценарий списка Manufacturers, каждый из которых содержит Id, CapacityCode, Price. Я хочу найти самую дешевую цену, но только для предметов, у которых у всех производителей одинаковые 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);

Мой вопрос:

Как добиться того же результата с точки зрения производительности и читабельности?

Ответы [ 2 ]

2 голосов
/ 29 апреля 2020

Вы можете сгруппировать производителей по CapacityCode с помощью ToLookup, получить максимальное число с помощью Max, группы фильтров с максимальным числом с помощью Where, сгруппировать группы в IEnumerable<Manufacturer> с помощью SelectMany и отсортировать цены с помощью 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();
2 голосов
/ 29 апреля 2020

IIU C ваш вопрос, нет необходимости группировать список 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;
...