Linq groupby对具有未知数目的键或键名的字典<string,string>的List的值

时间:2018-09-13 03:10:35

标签: c# linq

这是我花了几个小时而无法弄清楚的事情。基本上,我有一个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
}

编辑:我们最终选择了一条不同的路线

1 个答案:

答案 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());
                }
            }
        }
    }
}