Получить даты, содержащие все выбранные продукты

#c# #linq

#c# #linq

Вопрос:

У меня есть приложение-календарь, в котором вы выбираете различные комбинации продуктов — служба выходит и получает доступные даты на основе диапазона дат календаря. Дата является «доступной» только в том случае, если ВСЕ выбранные продукты доступны на определенную дату.

 class SelectedProduct
{
    public int ID { get; set; }
    public int Qty { get; set; }
}

class AvailableInventory
{
    public int ID { get; set; }
    public DateTime Date { get; set; }
}


// List of selected products from user 
List<SelectedProduct> SelectedProducts;

// populated from service with all dates for all products
List<AvailableInventory> AvailableInventory;
  

Я хочу иметь возможность сказать, получить список доступных запасов для каждой даты, который содержит запасы для всех идентификаторов в выбранных продуктах.

Это (нерабочий) код pusdo возможного решения, я просто недостаточно хорошо знаю linq, чтобы сделать это правильно

 var results = List<AvailableInventory>(); 

foreach (var group in AvailableInventory.GroupBy(x => x.Date))
{
    if (group.Contains(ALL ID's in SelectedProducts) 
    {
        results.AddRange(group); 
    } 

}
  

Комментарии:

1. Хорошо, что ты уже пробовал? Вы должны продемонстрировать свои усилия, а не просто просить нас написать код для вас.

2. слово хаха- я могу выполнить вышеописанное с помощью очень уродливого цикла — искал более элегантное решение LINQ — опубликую одну секунду.

3. является ли ваша Date собственность в AvailableInventory int или Date ?

4. Дата и время, извините, будут изменены.

5. хорошо, отправил ответ.

Ответ №1:

Это группирует запасы по дате (игнорируя часть даты), затем выбирает только те группы, которые содержат все выбранные идентификаторы продуктов, и, наконец, выбирает все доступные запасы для соответствующих групп.

 var results =
    AvailableInventory.GroupBy(i => i.Date.Date)
                      .Where(g => !SelectedProducts.Select(p => p.ID)
                                                   .Except(g.Select(i => i.ID))
                                                   .Any())
                      .SelectMany(g => g);
  

Результатом является коллекция AvailableInventory .

Ответ №2:

Вы можете сгруппировать по дате, а затем отфильтровать группы, в которых нет всех выбранных продуктов.

 // List of selected products from user 
List<SelectedProduct> SelectedProducts = new List<SelectedProduct> {
    new SelectedProduct { ID = 1, Qty = 1 },
    new SelectedProduct { ID = 2, Qty = 2 },
};


// populated from service with all dates for all products
List<AvailableInventory> AvailableInventory = new List<AvailableInventory> {
    new AvailableInventory { ID = 1, Date = new DateTime(2014, 04, 11) },
    new AvailableInventory { ID = 2, Date = new DateTime(2014, 04, 11) },
    new AvailableInventory { ID = 1, Date = new DateTime(2014, 04, 12) },
    new AvailableInventory { ID = 2, Date = new DateTime(2014, 04, 13) },
    new AvailableInventory { ID = 1, Date = new DateTime(2014, 04, 14) },
    new AvailableInventory { ID = 2, Date = new DateTime(2014, 04, 14) },                
};

var query = AvailableInventory.GroupBy(i => i.Date)
    .Where(g => SelectedProducts.All(s => g.Any(i => i.ID == s.ID)));

foreach(var group in query)
{
    Console.WriteLine("Date: {0}", group.Key);

    foreach(var inventory in group)
    {
        Console.WriteLine("  Available: {0}", inventory.ID);
    }
}
  

Это привело бы к:

 Date: 4/11/2014 12:00:00 AM
  Available: 1
  Available: 2
Date: 4/14/2014 12:00:00 AM
  Available: 1
  Available: 2
  

Ответ №3:

Я думаю, это то, что вы ищете. Попробуйте это

 var result = AvailableInventory.Where(i => SelectedProducts.Any(x => x.ID == i.ID)).GroupBy(o => o.Date)
           .Select(g => g.First()).ToList();
  

Это тестовые данные, которые я использовал на основе вашего определения класса для AvailableInventory и SelectedProduct

 // List of selected products from user 
List<SelectedProduct> SelectedProducts = new List<SelectedProduct> {
    new SelectedProduct { ID = 1, Qty = 2 },
    new SelectedProduct { ID = 2, Qty = 4 },
    new SelectedProduct { ID = 5, Qty = 10 }
};

// populated from service with all dates for all products
List<AvailableInventory> AvailableInventory = new List<AvailableInventory> {
    new AvailableInventory { ID = 1, Date = new DateTime(2014, 04, 01) },
    new AvailableInventory { ID = 2, Date = new DateTime(2014, 04, 02) },
    new AvailableInventory { ID = 3, Date = new DateTime(2014, 04, 02) },
    new AvailableInventory { ID = 4, Date = new DateTime(2014, 04, 10) },
    new AvailableInventory { ID = 5, Date = new DateTime(2014, 04, 10) }
};
  

Это должно дать вам только записи с ID = 1, ID = 2 and ID = 5 , потому что это то, что является общим для обоих AvailableInventory и SelectedProducts списков.

Ответ №4:

Это помогло бы, если бы вы действительно попробовали что-нибудь.

Учитывая это:

 List<SelectedProduct>    SelectedProducts   ;
List<AvailableInventory> AvailableInventory ;
  

Что-то вроде этого, вероятно, даст то, что вы хотите:

 int[] DatesWithAllSelectedProductsAvailable =
        AvailableInventory
        .GroupBy( x => x.Date )
        .Where ( g => g.All( x => SelectedProducts.Any( p => p.ID == x.ID ) ) )
        .Select( x => x.Key )
        .Distinct()
        .OrderBy( x => x )
        .ToArray()
        ;
  

Комментарии:

1. Поверьте мне, я пытался… свистящий звук, который раздался у меня над головой, был на одном уровне с 747.