How to flatten nested objects (LINQ)
我正在一个旧的winforms网格上做一些工作,我有两个模型,我正试图扁平化并分配给一个DataGridView。
这是我的样品模型。
1 2 3 4 5 6 7 8 9 10 11 12 | public class StockItem { public string StockName { get; set; } public int Id { get; set; } public List<Warehouse> Warehouses { get; set; } } public class Warehouse { public string WarehouseName { get; set; } public int Id { get; set; } } |
数据的工作方式是,必须首先创建一个仓库,然后将其分配给每个
我需要扁平化数据,以便网格显示
例子
1 2 3 | StockCode1 Warehouse1 Warehouse2 Warehouse3 StockCode2 Warehouse1 Warehouse2 StockCode2 Warehouse1 Warehouse3 |
我尝试通过LINQ查询来完成此操作,但只能为每个stockitemwarehouse获取一条记录。
您可以通过创建一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var warehouseNames = stocks .SelectMany(x => x.Warehouses.Select(y => y.WarehouseName)).Distinct(); var dt = new DataTable(); dt.Columns.Add("StockCode"); foreach (var name in warehouseNames) { dt.Columns.Add(name); } foreach (var stock in stocks) { var row = dt.NewRow(); row["StockCode"] = stock.Id; foreach (var warehouse in stock.Warehouses) { row[warehouse.WarehouseName] = warehouse.Id; } dt.Rows.Add(row); } |
像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | var availableWarehouses = new [] { new Warehouse { WarehouseName ="Warehouse1", Id = 1 }, new Warehouse { WarehouseName ="Warehouse2", Id = 2 }, new Warehouse { WarehouseName ="Warehouse3", Id = 3 } }; var stocks = new [] { new StockItem { StockName ="StockCode1", Id = 1, Warehouses = new List<Warehouse> { availableWarehouses[0], availableWarehouses[1], availableWarehouses[2] } }, new StockItem { StockName ="StockCode2", Id = 2, Warehouses = new List<Warehouse> { availableWarehouses[0], availableWarehouses[1] } }, new StockItem { StockName ="StockCode3", Id = 3, Warehouses = new List<Warehouse> { availableWarehouses[0], availableWarehouses[2] } } }; var flatten = stocks.Select(item => new { StockName = item.StockName, WarehousesNames = availableWarehouses.Select(warehouse => item.Warehouses.Contains(warehouse) ? warehouse.WarehouseName :" ") .Aggregate((current, next) => current +"\t" + next) }); foreach(var item in flatten) { Console.WriteLine("{0}\t{1}", item.StockName, item.WarehousesNames); } |
我不建议这样做,但您可以使用动态对象创建具有所需形状的对象。这样做不是一种常见的C模式。这在诸如python或javascript之类的语言中更常见。
C是一种强类型语言,只有在绝对必要的时候才应该考虑进入动态对象的世界(考虑解析JSON blob)。我强烈认为你需要重新评估你需要做什么,并从另一个角度来对待它。
这应该给你你所需要的:
1 2 3 4 5 6 7 | var flattened = stockItems .Select(x => new { StockName = x.StockName, WarehouseNames = x.Warehouses .Select(y => y.WarehouseName) .ToList() }) .ToList(); |
它将导致包含
对于这些示例数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | List<StockItem> stockItems = new List<StockItem> { new StockItem { StockName ="A", Id = 1, Warehouses = new List<Warehouse> { new Warehouse { Id = 1, WarehouseName ="x" }, new Warehouse { Id = 2, WarehouseName ="y" } } }, new StockItem { StockName ="B", Id = 2, Warehouses = new List<Warehouse> { new Warehouse { Id = 3, WarehouseName ="z" }, new Warehouse { Id = 4, WarehouseName ="w" } } } }; |
我得到了以下结果: