#c# #linq
#c# #linq
Вопрос:
Я конвертирую некоторый код в LINQ, одновременно изучая, в какой степени LINQ может выполнить.
Можно ли сжать следующий код в один запрос или метод LINQ?
Dictionary<string, ItemPack> consolidated = new Dictionary<string, ItemPack>();
foreach (var product in Products)
{
foreach (var smallpack in product.ItemPacks)
{
ItemPack bigpack;
if (consolidated.TryGetValue(smallpack.ItemCode, out bigpack))
{
// the big pack quantity = quantity for making one product * the number of that product
bigpack.Quantity = smallpack.Quantity * product.Quantity;
// References: we make sure that the small pack is using the Item in the big pack.
// otherwise there will be 2 occurance of the same Item
smallpack.Item = bigpack.Item;
}
else
{
bigpack = new ItemPack(smallpack); // Copy constructor
bigpack.Quantity = smallpack.Quantity * product.Quantity;
consolidated.Add(smallpack.ItemCode, bigpack);
}
}
}
return consolidated;
На английском языке каждый продукт состоит из нескольких предметов разного количества. Эти элементы сгруппированы по коду элемента и упакованы в небольшие пакеты. Эти небольшие пакеты поставляются вместе как единый продукт. Существует много разных продуктов. Один элемент может использоваться в разных продуктах.
Теперь у меня есть список продуктов и количество, необходимое для каждого для отправки. Я хочу, чтобы оператор LINQ консолидировал единый список элементов и их количества.
Я зашел так далеко, но, похоже, это не работает:
var packsQuery = from product in Products
from smallpack in product.ItemPacks
select new {Item = smallpack.Item, Quantity = smallpack.Quantity * product.Quantity};
foreach (var pack in packsQuery)
{
consolidated.Add(pack.Item.ItemCode, new ItemPack(pack.Item, pack.Quantity));
}
Если я сначала сгруппирую, я не смогу выбрать элемент по его количеству. Если я выбираю первым, я теряю группировку. История с курицей и яйцом?
РЕДАКТИРОВАТЬ: Полезное примечание: smallpack имеет тип ItemPack, который выглядит следующим образом
public class ItemPack
{
Item { get; } // The item in this pack, which *must* be a shared reference across all objects that uses this Item. So that change in Item properties are updated everywhere it is used. e.g. Price.
ItemCode { get; } // The item code
Quantity { get; } // The number of such Item in this pack.
}
Ответ №1:
var query = (from product in Products
from smallPack in product.ItemPacks
select new
{
ItemCode = smallPack.ItemCode,
Item = smallPack.Item,
Quantity = smallPack.Quantity * product.Quantity,
})
.GroupBy(p => p.ItemCode)
.Select(p => new
{
ItemCode = p.Key,
Item = p.FirstOrDefault(),
Quantity = p.Sum(x=>x.Quantity)
})
.ToDictionary(p=>p.ItemCode);
Ответ №2:
Спасибо, что указали мне правильное направление. Мне удалось разработать полную версию синтаксиса запроса:
var query = from product in Products
from smallpack in product.ItemPacks
select new {
Item = smallpack.Item,
Quantity = smallpack.Quantity * product.Quantity
} into mediumpack
group mediumpack by mediumpack.Item.ItemCode into bigpack
select new {
Item = bigpack.First().Item, // shared reference
Quantity = bigpack.Sum(a => a.Quantity);
}
query.ToDictionary(...);
Любые комментарии относительно того, хорошо ли это?
Комментарии:
1. Да, это то же самое, что и у меня, так что все в порядке.