c# - 如何在对子键进行分组时使用 LINQ 加入两个父/子对象列表
问题描述
我想创建一个列表并将CustomerOrder
其分组quantity
。item_id
该代码几乎可以工作,但它没有组合在item_id
.
我也认为在性能/内存使用方面有问题。它在总列表大小约为 1000 时有效,但当它达到 ~30,000 时,它会出现内存问题。
我怀疑问题出在“选择新客户”上。我可能不应该使用ToList()
IEnumerable,我不能这样做。我认为这GroupJoin
将是要走的路,但我也无法让它发挥作用。我发现使用组连接的示例在子表中有一个“外键”值,我没有。
public class CustomerOrder
{
public int order_id { get; set; }
public List<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{
public int item_id { get; set; }
public int quantity { get; set; }
}
public class Program
{
public static void Main()
{
List<CustomerOrder> list1 = new List<CustomerOrder>()
{new CustomerOrder{order_id = 1, OrderLines = new List<OrderLine>()
{new OrderLine()
{item_id = 123, quantity = 2}, new OrderLine()
{item_id = 456, quantity = 3}}}};
List<CustomerOrder> list2 = new List<CustomerOrder>()
{new CustomerOrder{order_id = 1, OrderLines = new List<OrderLine>()
{new OrderLine()
{item_id = 456, quantity = 2}, new OrderLine()
{item_id = 789, quantity = 3}}}};
var orderdetails =
from g in list1.Concat(list2).GroupBy(x => x.order_id) select new CustomerOrder { order_id = g.Key, OrderLines = g.SelectMany(x => x.OrderLines).ToList() };
foreach (var item in orderdetails)
{
Console.WriteLine(item.order_id);
foreach (var line in item.OrderLines)
{
Console.WriteLine("{0} {1}", line.item_id, line.quantity);
}
}
}
}
当前输出为:
1
123 2
456 3
456 2
789 3
我想要的输出是:
1
123 2
456 5
789 3
每个列表都应该是唯一的,order_id
但在order_lines
. 一个列表几乎总是比另一个大得多。30K 样本的当前比率为 29,500:500。
解决方案
你OrderLines
也需要分组:
var orderdetails =
from g in list1.Concat(list2).GroupBy(x => x.order_id)
select new CustomerOrder
{
order_id = g.Key,
OrderLines = g
.SelectMany(x => x.OrderLines)
.GroupBy(ol => ol.item_id)
.Select(g => new OrderLine
{
item_id = g.Key, quantity = g.Sum(gg => gg.quantity)
})
.ToList()
};
至于处理 30k+ 条目的性能(特别是如果保证第一个集合具有唯一的顺序),我认为更好的方法是从第一个集合创建一个字典,在第二个集合上切换到for
/foreach
循环并在其中添加/更新字典中的元素(包括子对象)而不是创建新对象。
或者至少尝试:
var orderdetails = list1
.Concat(list2)
.GroupBy(x => x.order_id)
.Select(g =>
{
// may be better to materialize group,
// and use it for First and SelectMany
var order = g.First();
order.OrderLines = g
.SelectMany(og => og.OrderLines)
.GroupBy(ol => ol.item_id)
.Select(olg =>
{
var line = olg.First();
line.quantity = olg.Sum(ol => ol.quantity);
return line;
})
.ToList();
return order;
})
推荐阅读
- apache-nifi - PrometheusReportingTask 未在 NiFi 中发出指标
- asp.net - 以编程方式重新启动 .NET Web 应用程序的最快方法
- javascript - jQuery.animate(...) 无法正常工作
- c - 如何通过使用 getchar 按下箭头键来避免阅读奇怪的符号?
- database - Linux服务器中PERL代码中的文件扩展名类型
- javascript - 带有 $.getJSON() 的 canvasJS 出现 CORB 错误
- python - 如何将一组中的非空值分配给熊猫组中的所有行?
- wolfram-mathematica - 无法在 wolfram-mathmica 中完成傅立叶分析?
- python - 如何处理 PyTorch 的 LSTM 模块中的可变大小序列?
- c++ - 无法在 C++ 中打印矢量对象数据成员值