Как консолидировать результаты из нескольких IEnumerable с помощью LINQ

#c# #linq #ienumerable

#c# #linq #ienumerable

Вопрос:

У меня могло бы быть несколько (до 5) IEnumerable<ResortSupplier> и я хотел бы объединить их в одну IEnumerable<ResortSupplier> группировку по коду поставщика. Мои объекты выглядят следующим образом:

Вот мои объекты:

 [Serializable]
public class ResortSupplier
{
    public string SupplierCode { get; set; }
    public IList<Product> ResortProducts { get; set; }
}

[Serializable]
public class Product
{
    public string Code { get; set; }
    //Other fields... 
    public IList<PerPricing> PricingDetail { get; set; }
}

[Serializable]
public class PerPricing
{
    //Other fields..
    public decimal? Price { get; set; }
    public Error PricingError { get; set; }
}
  

Данные в нескольких IEnumerable могут выглядеть следующим образом:

 ----------------------------------------
IEnumerable<ResortSupplier> - 1

Hyatt Resort
  Standard Room
    PricingDetail-1
  Superior Room         
    PricingDetail-1

Sandals Resort
  Standard Room
    PricingDetail-1
  Delux Room            
    PricingDetail-1

----------------------------------------
IEnumerable<ResortSupplier> - 2

Hyatt Resort
  Standard Room
    PricingDetail-2
  Superior Room         
    PricingDetail-2
  One Bed Room Suit
    PricingDetail-2

Sandals Resort
  Standard Room
    PricingDetail-2
  Honeymoon Suit            
    PricingDetail-2
----------------------------------------
IEnumerable<ResortSupplier> - 3
.....
----------------------------------------
IEnumerable<ResortSupplier> - 4
.....
----------------------------------------
IEnumerable<ResortSupplier> - 5
.....
----------------------------------------
  

Мой консолидированный результат должен содержать:

 IEnumerable<ResortSupplier> - Consolidated

Hyatt Resort
  Standard Room
    PricingDetail-1
    PricingDetail-2
  Superior Room         
    PricingDetail-1
    PricingDetail-2
  Bed Room Suit
    PricingDetail-2

Sandals Resort
  Standard Room
    PricingDetail-1
    PricingDetail-2
  Delux Room            
    PricingDetail-1
  Honeymoon Suit            
    PricingDetail-2

----------------------------------------
  

Каков наилучший способ справиться с этим? Я попробовал простой IEnumerable.Предложения Union и GroupBy, но не дают мне желаемых результатов.

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

1. К вашему сведению, объединение удалит дубликаты.

Ответ №1:

Если я вас правильно понимаю, вы должны использовать Concat, чтобы собрать их в одну большую коллекцию, затем вы можете группировать, как хотите

 IEnumerable<ResortSupplier> master = 
    result1.Concat(result2).Concat(result3); //etc
  

Затем сгруппируйте, как обычно:

 var resultGrouped = master.GroupBy(rs => rs.SupplierCode);
  

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

1. Адам, пожалуйста. смотрите мои комментарии к сообщению Мартиньо.

2. Я думаю, что ваш вопрос сформулирован неправильно. Вызов concat для ваших 5 коллекций сведет их в одну. Группировка этой огромной коллекции будет … группировать it…by все, что вы укажете. Чего именно вы ожидаете и что происходит?

3. Адам, возможно, я не очень четко сформулировал свой вопрос, но мой пример показывает, какими должны быть мои ожидаемые результаты. Прошу прощения за путаницу. Решение Ani сработало для меня. Спасибо.

Ответ №2:

Я думаю, вы хотите что-то вроде:

 // You can construct this with an array if it isn't already in this form.
IEnumerable<IEnumerable<ResortSupplier>> supplierLists = ...

var query = from suppliers in supplierLists
            from supplier in suppliers
            group supplier by supplier.SupplierCode into g

            let products = g.SelectMany(s => s.ResortProducts)
                            .GroupBy(p => p.Code)
                            .Select(prodGroup => new Product
                                    {
                                       Code = prodGroup.Key,
                                       PricingDetail = prodGroup
                                                       .SelectMany(p => p.PricingDetail)
                                                       .ToList()
                                    })

            select new ResortSupplier
            {
                SupplierCode  = g.Key, 
                ResortProducts = products.ToList()                              
            };
  

Хотя это действительно ужасно выглядящий запрос. Я настоятельно рекомендую разложить различные компоненты запроса на отдельные методы (с правильными именами).

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

1. Ани, я мог бы получить несколько, IEnumerable<ResortSupplier> но не IEnumerable<IEnumerable<ResortSupplier>> . Вы хотите, чтобы я сначала собрал IEnumerable<IEnumerable<ResortSupplier>> из всех IEnumerable<ResortSupplier> ?

2. @Alex: Да. Например: var supplierLists = new[] { supplierList1, supplierList2, ... };

3. Ани, это сработало. Спасибо. У меня также есть поле «LowestPrice» в ResortSupplier , которое будет содержать самую низкую цену из всех p.PricingDetail. Как я могу заполнить это поле? Я думаю, что мне, возможно, придется использовать .Min(p => p.Price) функцию LINQ, но мне сложно создать запрос.

4. Я получил самую низкую цену SelectMany(p => p.PricingDetail).Min(p => p.Price) , НО я хочу самую низкую ненулевую цену, если я использую предложение where, такое как .Where(l => l.Price > 0).Min(p => p.Price) , оно удаляет элементы с нулевой ценой, предложение where действует как фильтр и удаляет ненулевые записи. Я хочу сохранить все записи нетронутыми, а также получить самую низкую ненулевую цену.