用Linq分组字典

本文关键字:字典 Linq | 更新日期: 2023-09-27 18:18:08

我有两个List<Dictionary<string, string>>

List<Dictionary<string, string>> ListdicA = new List<Dictionary<string, string>>();
Dictionary<string, string> dic1 = new Dictionary<string, string>();
dic1.Add("Type1", "1");
dic1.Add("Type2", "A");
dic1.Add("Type3", "X");
Dictionary<string, string> dic2 = new Dictionary<string, string>();
dic2.Add("Type1", "2");
dic2.Add("Type2", "B");
dic2.Add("Type3", "Y");
ListdicA.Add(dic1);
ListdicA.Add(dic2);
List<Dictionary<string, string>> ListdicB = new List<Dictionary<string, string>>();
Dictionary<string, string> dic3 = new Dictionary<string, string>();
dic3.Add("Type1", "1");
dic3.Add("Type2", "C");
dic3.Add("Type3", "X");
Dictionary<string, string> dic4 = new Dictionary<string, string>();
dic4.Add("Type1", "2");
dic4.Add("Type2", "D");
dic4.Add("Type3", "Z");
ListdicB.Add(dic3);
ListdicB.Add(dic4);

我想合并两个列表,并按键对值进行分组。结果是一个List<Dictionary<string, List<string>>>。首先,我想合并两个列表:

Type1 1
Type2 A
Type3 X
Type1 2
Type2 B
Type3 Y
Type1 1
Type2 C
Type3 X
Type1 2
Type2 D
Type3 Z

按键分组,结果如下:

Type1 1
Type2 A C
Type3 X X
Type1 2
Type2 B D
Type3 Y Z

用Linq分组字典

基于问题的更新:

这是非常复杂的(至少对我来说是)。我展示了这些步骤,并且我把每个LINQ放在括号内,它们完成了这项工作的一部分。

1)你必须连接两个列表。(ListdicA.Concat(ListdicB))

2)按每个字典中Type1键的值对所有字典进行分组。(GroupBy(x => x["Type1"]))

3) Unwrap all Items IGrouping<string,Dictionary<string,string>> to KeyValuePair<string,string> (SelectMany(y => y))

4)再次按key分组键值对,以便将相同键的值连接在一起(GroupBy(y => y.Key))

5) Unwrap IGrouping<string,KeyValuePair<string,string>> into IEnumerable<KeyValuePair<string,List<string>>> (Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList())))

6)转换IEnumerable<IEnumerable<KeyValuePair<string,List<string>>>>IEnumerable<Dictionary<string,List<string>>> (Select(x => x.ToDictionary(y => y.Key, y => y.Value)))

7)最后将IEnumerable<Dictionary<string,List<string>>>转换为List<Dictionary<string, List<string>>> (ToList())

string groupby = "Type1";
List<Dictionary<string, List<string>>> result =
    ListdicA.Concat(ListdicB).GroupBy(x => x[groupby]).Select(x =>
        x.SelectMany(y => y) // Put .Distinct() here to remove duplicates.(optional)
            .GroupBy(y => y.Key).Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList())))
                .Select(x => x.ToDictionary(y => y.Key, y => y.Value)).ToList();
foreach (var d in result)
{
    foreach (var k in d)
    {
        Console.Write(k.Key + " : ");
        foreach (var l in k.Value)
        {
            Console.Write(l + " ");
        }
        Console.WriteLine();
    }
}

输出
Type1 1 1
Type2 A C
Type3 X X
Type1 2 2
Type2 B D
Type3 Y Z

正如我在注释(代码内部)中提到的如果你删除注释并将.Distinct()放在那里它将删除重复的

List<Dictionary<string, List<string>>> result =
    ListdicA.Concat(ListdicB).GroupBy(x => x[groupby]).Select(x => x.SelectMany(y => y)
        .Distinct().GroupBy(y => y.Key)
            .Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList())))
                .Select(x => x.ToDictionary(y => y.Key, y => y.Value)).ToList();

将输出。

Type1 1
Type2 A C
Type3 X
Type1 2
Type2 B D
Type3 Y Z

如果你不想丢失X,那么你需要一个自定义的Distinct。你将需要这门课。(linq是从这里截取和编辑的)

public static class SomeMoreLinq
{
    public static IEnumerable<TSource> DistinctIf<TSource>
        (this IEnumerable<TSource> source, Func<TSource, bool> keySelector)
    {
        HashSet<TSource> seenKeys = new HashSet<TSource>();
        foreach (TSource element in source)
        {
            if (seenKeys.Add(element) || !keySelector(element))
            {
                yield return element;
            }
        }
    }
}

然后在你的查询中使用它。

List<Dictionary<string, List<string>>> result =
    ListdicA.Concat(ListdicB).GroupBy(x => x[groupby]).Select( x => x.SelectMany(y => y)
        .DistinctIf(y => y.Key == groupby).GroupBy(y => y.Key)
            .Select(y => new KeyValuePair<string, List<string>>(y.Key, y.Select(z => z.Value).ToList())))
                .Select(x => x.ToDictionary(y => y.Key, y => y.Value)).ToList();

将输出。

Type1 1
Type2 A C
Type3 X X
Type1 2
Type2 B D
Type3 Y Z

如果你有任何问题,请提出来。

虽然这完全融化了我的心,但这是一个很好的实践!

如果你这样做

ListdicA.Zip(ListdicB, (a,b) => a.Concat(b)
.GroupBy(x => x.Key)
.Select (g => new
              {
                   g.Key, 
                   Values = g.SelectMany(d => d.Value).Distinct()
              } ))

你会得到这样的结果:

Type 1   1
Type 2   A
         C
Type 3   X
Type 1   2
Type 2   B
         D
Type 3   Y
         Z

我不确定你的X X结果是故意的,还是打字错误。如果它是有意的,我应该添加更多的逻辑