这是我花了几个小时而无法弄清楚的事情。基本上,我有一个List<object>
,并且该列表中的每个对象都有一个Dictionary<long, Dictionary<string,string>>
。 Dictionary<string,string>
是需要分组的数据对集。 linq是否有一种方法可以迭代List<object>
键的数字/名称未知的Dictionary<string,string>
并使用group by?
对于上下文,每个字典实际上是一行数据,而字符串键值对实际上是列/数据。不幸的是,我无法更改接收这些数据的方式。
我可以找到的大多数示例似乎仅适用于DataTables,或者为某些列名称进行了硬编码。如果字典在该列表中的对象之内是不可能的,那么如果只是List<Dictionary<string,string>>
可以做到吗?
出于此代码段的目的,请假定变量AllDataList是ContainerClass对象的完整列表。例行的投影是从以下地方借来的: https://www.codeproject.com/Questions/141367/Dynamic-Columns-from-List-using-LINQ
不幸的是,我不能为此引入第三方图书馆。
public class ContainerClass
{
public Dictionary<long, Dictionary<string, string>> data;
public ContainerClass()
{
data = Dictionary<long, Dictionary<string, string>>;
data.add(0,new Dictionary<string,string>());
}
}
private dynamic Projection(object a, IEnumerable<string> props)
{
if (a == null)
{
return null;
}
IDictionary<string, object> res = new System.Dynamic.ExpandoObject();
var type = a.GetType();
foreach (var pair in props.Select(n => new {
Name = n,
Property = type.GetProperty(n)
}))
{
res[pair.Name] = pair.Property.GetValue(a, new object[0]);
}
return res;
}
public void DoStuff()
{
List<string> cols = new List<string>();
//normally cols would be determined at runtime
cols.add("Column1");
cols.add("Column2");
cols.add("Column3");
List<ContainerClass> res = (List<ContainerClass>) this.AllDataList.GroupBy(x => new[] {
Projection(x.data,cols)
}).Select(y =>Projection(y, cols)); //unsure if the select is necessary
}
编辑:我们最终选择了一条不同的路线
答案 0 :(得分:0)
你有这样的东西吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(long));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(string));
dt.Rows.Add(new object[] { 1, "abc", "mno" });
dt.Rows.Add(new object[] { 1, "def", "mnp" });
dt.Rows.Add(new object[] { 1, "def", "mnq" });
dt.Rows.Add(new object[] { 2, "abc", "mnr" });
dt.Rows.Add(new object[] { 2, "abd", "mns" });
dt.Rows.Add(new object[] { 3, "abe", "mnt" });
dt.Rows.Add(new object[] { 3, "abf", "mnu" });
dt.Rows.Add(new object[] { 4, "abc", "mnv" });
dt.Rows.Add(new object[] { 4, "ade", "mnw" });
Dictionary<long, Dictionary<string, string>> dict = dt.AsEnumerable()
.GroupBy(x => x.Field<long>("ID"), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Field<string>("Name"), b => b.Field<string>("Value"))
.ToDictionary(a => a.Key, b => b.FirstOrDefault())
);
//Now back to a datatable
DataTable dt2 = new DataTable();
dt2.Columns.Add("Col A", typeof(long));
dt2.Columns.Add("Col B", typeof(string));
dt2.Columns.Add("Col C", typeof(string));
foreach(long id in dict.Keys)
{
foreach (KeyValuePair<string, string> value in dict[id])
{
dt2.Rows.Add(new object[] {id, value.Key, value.Value});
}
}
}
}
}
这是另一种可行的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(long));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Value", typeof(string));
dt.Rows.Add(new object[] { 1, "abc", "mno" });
dt.Rows.Add(new object[] { 1, "def", "mnp" });
dt.Rows.Add(new object[] { 1, "def", "mnq" });
dt.Rows.Add(new object[] { 2, "abc", "mnr" });
dt.Rows.Add(new object[] { 2, "abd", "mns" });
dt.Rows.Add(new object[] { 3, "abe", "mnt" });
dt.Rows.Add(new object[] { 3, "abf", "mnu" });
dt.Rows.Add(new object[] { 4, "abc", "mnv" });
dt.Rows.Add(new object[] { 4, "ade", "mnw" });
Dictionary<long, Dictionary<string, List<DataRow>>> dict = dt.AsEnumerable()
.GroupBy(x => x.Field<long>("ID"), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Field<string>("Name"), b => b)
.ToDictionary(a => a.Key, b => b.ToList())
);
//Now back to a datatable
DataTable dt2 = new DataTable();
foreach(long id in dict.Keys)
{
foreach (KeyValuePair<string, List<DataRow>> value in dict[id])
{
dt2.Merge(value.Value.CopyToDataTable());
}
}
}
}
}