使用LINQ,将对象组合列表分组到另一个对象列表中

iaqfqrcu  于 2024-01-03  发布在  其他
关注(0)|答案(2)|浏览(227)

更新:将类名更改为ComboProduct和Product,以便清除

  1. public class Product
  2. {
  3. public string Name {get; set;}
  4. }
  5. public class ComboProduct
  6. {
  7. public int Id;
  8. public List<Product> ProductList {get; set;}
  9. }
  10. public class ProductStock
  11. {
  12. public Product Product {get; set;}
  13. public int Quantity {get; set;}
  14. public double Price {get; set;}
  15. }
  16. public class Result
  17. {
  18. public int ComboProductId {get; set;}
  19. public int Quantity {get; set;}
  20. public double Price {get; set;}
  21. }

个字符
如何使用Linq将ProductStock分组为一个新的组合列表,如下所示:
{ ComboProductId,Price:priceA + priceB + priceC Quantity:Min(quantityA,quantityB,quantityC)}
我尝试使用C#算法,但希望帮助使用Linq实现它。

  1. Expected result:
  2. | ComboProductId Price Quantity
  3. (A1,B1,C1) | 1 140 5
  4. (A2,B1,C1) | 1 145 25
  5. (A2,B2,C1) | 1 150 9
  6. (A3,B1,C2) | 1 120 25

a11xaf1n

a11xaf1n1#

  • 更新的答案**此答案反映了大约在最初发布此答案的原始版本(详见下文)的同时对班级结构所做的更改。*

为了更容易地跟踪提供结果的数据,我在ProductStockResult类中各添加了一个属性。

  1. public class ProductStock
  2. {
  3. public int ProductStockId {get; set;} // Added
  4. public Product Product {get; set;}
  5. public int Quantity {get; set;}
  6. public double Price {get; set;}
  7. }
  8. public class Result
  9. {
  10. public int ComboProductId {get; set;}
  11. public List<ProductStock> StockCombination {get; set;} // Added
  12. public int Quantity {get; set;}
  13. public double Price {get; set;}
  14. }

字符串
以下代码将:
1.对于所选ComboProduct中的每个Product,收集匹配ProductStock项目的列表。
1.将数据组织为列表的列表的列表,其中:(a)外部列表是产品分组,每个产品有一个物料。(B)中间列表表示所有组合(最初,当前产品组中的每个库存物料有一个物料)。(c)内部列表表示此组合的所有构成库存物料(最初,只有一个库存物料)。
1.使用.Aggregate()重复执行初始组与其余组的叉积。一个组中的N个组合与另一个组中的M个组合的叉积将生成N * M个新组合。系统将建立起库存物料的内部列表,以包括两个组合中的物料。
1.此时的结果将是一个库存项目列表。外部列表代表所有组合。内部列表包含所有构成此组合的库存项目。
1.最后,将这些组合Map到具有ComboProductId、ProductStock列表、最小数量和总价的Result对象。

  1. List<Result> results = comboProduct.ProductList
  2. .Select(p =>
  3. productStocks
  4. .Where(ps => ps.Product == p)
  5. .Select(ps => new List<ProductStock>{ps})
  6. .ToList()
  7. )
  8. .Aggregate((group1, group2) =>
  9. group1.SelectMany(list1 =>
  10. group2.Select(list2 =>
  11. list1.Concat(list2).ToList()
  12. )
  13. )
  14. .ToList()
  15. )
  16. .Select(stockCombination => new Result {
  17. ComboProductId = comboProduct.Id,
  18. StockCombination = stockCombination,
  19. Quantity = stockCombination.Min(ps => ps.Quantity),
  20. Price = stockCombination.Sum(ps => ps.Price)
  21. })
  22. .ToList();


结果如下:
| 组合产品标识|库存物品|价格|数量|
| --|--|--|--|
| 1 |(A1、B4、C6)| 140 | 5 |
| 1 |(A1、B4、C7)| 110 | 5 |
| 1 |(A1、B4、C8)| 130 | 5 |
| 1 |(A1、B5、C6)| 145 | 5 |
| 1 |(A1、B5、C7)| 115 | 5 |
| 1 |(A1、B5、C8)| 135 | 5 |
| 1 |(A2、B4、C6)| 145 | 25 |
| 1 |(A2、B4、C7)| 115 | 25 |
| 1 |(A2、B4、C8)| 135 | 25 |
| 1 |(A2、B5、C6)| 150 | 9 |
| 1 |(A2、B5、C7)| 120 | 9 |
| 1 |(A2、B5、C8)| 140 | 9 |
| 1 |(A3、B4、C6)| 150 | 25 |
| 1 |(A3、B4、C7)| 120 | 25 |
| 1 |(A3、B4、C8)| 140 | 25 |
| 1 |(A3、B5、C6)| 155 | 9 |
| 1 |(A3、B5、C7)| 125 | 9 |
| 1 |(A3、B5、C8)| 145 | 9 |
请参阅this .NET fiddle,以取得包含其他测试数据的示范。

  • 原始答案:*此答案是在OP对问题进行重大重写之前准备的,在此过程中更改了大部分类名和属性。此答案使用了原始发布的类。

我有两种可能的解决方案。这两种方案都是从对初始数据项进行分组并分配序号开始的。每个组都可以被看作是一个要与其他组交叉联接的项表。然后使用.Aggregate()函数在组之间重复应用交叉联接。结果是所有所需组合的列表。
这两种方法(如下所示)的区别在于,第一种方法在每个组中构建一个ClassA结果对象的初始集,然后在每次类应用迭代时生成新的组合ClassA对象。第二种方法只是根据初始数据建立起一个有贡献的ClassB项的列表,并将最终ClassA结果的构造推迟到所有的交叉连接已完成。
最终结果是相同的,但可能存在性能差异。

  1. List<ClassA> combinations2 = classBList
  2. .GroupBy(b => b.ClassAItem)
  3. .OrderBy(g => g.Key)
  4. .Select(g => g.Select((b, i) =>
  5. new List<ClassB> {
  6. new ClassB {
  7. ClassAItem = b.ClassAItem + (i + 1).ToString(), // Rename
  8. Quantity = b.Quantity,
  9. Price = b.Price
  10. }
  11. })
  12. .ToList()
  13. )
  14. .Aggregate((group1, group2) =>
  15. group1.SelectMany(list1 =>
  16. group2.Select(list2 =>
  17. list1.Concat(list2).ToList()
  18. )
  19. )
  20. .ToList()
  21. )
  22. .Select(list => new ClassA {
  23. Items = list.Select(item => item.ClassAItem).ToList(),
  24. Quantity = list.Min(item => item.Quantity),
  25. Price = list.Sum(item => item.Price)
  26. })
  27. .ToList();


结果如下:
| 项目|价格|数量|
| --|--|--|
| (A1、B1、C1)| 140 | 5 |
| (A1、B1、C2)| 110 | 5 |
| (A1、B1、C3)| 130 | 5 |
| (A1、B2、C1)| 145 | 5 |
| (A1、B2、C2)| 115 | 5 |
| (A1、B2、C3)| 135 | 5 |
| (A2、B1、C1)| 145 | 25 |
| (A2、B1、C2)| 115 | 25 |
| (A2、B1、C3)| 135 | 25 |
| (A2、B2、C1)| 150 | 9 |
| (A2、B2、C2)| 120 | 9 |
| (A2、B2、C3)| 140 | 9 |
| (A3、B1、C1)| 150 | 25 |
| (A3、B1、C2)| 120 | 25 |
| (A3、B1、C3)| 140 | 25 |
| (A3、B2、C1)| 155 | 9 |
| (A3、B2、C2)| 125 | 9 |
| (A3、B2、C3)| 145 | 9 |
请注意,有几行中的Quantity值与原始post预期结果不匹配,但我相信这些结果是正确的,而原始post预期结果是错误的。
请参见this .NET Fiddle

展开查看全部
ifmq2ha2

ifmq2ha22#

如果我清楚地理解了这个要求。你可以这样做。

  1. List<Product> products = new List<Product>
  2. {
  3. new Product { Name = "A" },
  4. new Product { Name = "B" },
  5. new Product { Name = "C" }
  6. // Add other products as needed
  7. };
  8. List<ComboProduct> comboProducts = new List<ComboProduct>
  9. {
  10. new ComboProduct { Id = 1, ProductList = new List<Product> { products[0], products[1], products[2] } }
  11. // Add other combo products as needed
  12. };
  13. List<ProductStock> productStocks = new List<ProductStock>
  14. {
  15. new ProductStock { Product = products[0], Quantity = 5, Price = 10 },
  16. new ProductStock { Product = products[0], Quantity = 60, Price = 15 },
  17. new ProductStock { Product = products[0], Quantity = 55, Price = 20 },
  18. new ProductStock { Product = products[1], Quantity = 25, Price = 30 },
  19. new ProductStock { Product = products[1], Quantity = 9, Price = 35 },
  20. new ProductStock { Product = products[2], Quantity = 40, Price = 100 },
  21. new ProductStock { Product = products[2], Quantity = 68, Price = 70 },
  22. new ProductStock { Product = products[2], Quantity = 27, Price = 90 }
  23. // Add other product stocks as needed
  24. };
  25. var result = from comboProduct in comboProducts
  26. from productStocksGroup in productStocks
  27. .Where(ps => comboProduct.ProductList.Any(cp => cp.Name == ps.Product.Name))
  28. .GroupBy(ps => ps.Product.Name)
  29. select new Result
  30. {
  31. ComboProductId = comboProduct.Id,
  32. Quantity = productStocksGroup.Min(ps => ps.Quantity),
  33. Price = productStocksGroup.Sum(ps => ps.Price)
  34. };

字符串

展开查看全部

相关问题