【问题标题】:Group dictionaries with Linq使用 Linq 对字典进行分组
【发布时间】:2016-01-16 20:12:52
【问题描述】:

我有两个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&lt;Dictionary&lt;string, List&lt;string&gt;&gt;&gt;。首先,我想合并两个列表:

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

【问题讨论】:

  • 我不确定我是否理解分组的逻辑条件。您能否修改您的问题以包含有关应如何进行不同分组的详细信息?
  • 我想合并两个 List 并按 Type1 @Luc Morin 分组
  • 您需要使用外连接来连接两个字典的键,因为您需要包含两个字典的所有键。请参阅以下网页:code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
  • 为什么是X X(而你没有1 1)?

标签: c# linq list dictionary collections


【解决方案1】:

如果你这样做

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 结果是故意的还是错字。如果是这样,我应该添加更多逻辑。

【讨论】:

    【解决方案2】:

    基于问题更新:

    这是非常复杂的(至少对我来说是这样)。我展示了这些步骤,并且我将每个 LINQ 放在括号内,以完成该工作。

    1) 你必须加入两个列表。 (ListdicA.Concat(ListdicB))

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

    3) 解开所有项目 IGrouping&lt;string,Dictionary&lt;string,string&gt;&gt;KeyValuePair&lt;string,string&gt; (SelectMany(y =&gt; y))

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

    5) 将IGrouping&lt;string,KeyValuePair&lt;string,string&gt;&gt; 解包为IEnumerable&lt;KeyValuePair&lt;string,List&lt;string&gt;&gt;&gt; (Select(y =&gt; new KeyValuePair&lt;string, List&lt;string&gt;&gt;(y.Key, y.Select(z =&gt; z.Value).ToList())))

    6) 将IEnumerable&lt;IEnumerable&lt;KeyValuePair&lt;string,List&lt;string&gt;&gt;&gt;&gt; 转换为IEnumerable&lt;Dictionary&lt;string,List&lt;string&gt;&gt;&gt; (Select(x =&gt; x.ToDictionary(y =&gt; y.Key, y =&gt; y.Value)))

    7) 最后将IEnumerable&lt;Dictionary&lt;string,List&lt;string&gt;&gt;&gt; 转换为List&lt;Dictionary&lt;string, List&lt;string&gt;&gt;&gt; (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 was taken and edited from here)

    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
    

    如果您有任何问题,请随时提出。

    虽然这完全融化了我的想法,但这是一个很好的做法!

    【讨论】:

    • 非常感谢,但我想要的结果是 List>>, is not Dictionary>
    • 你能解释一下你的逻辑吗?您的输出似乎完全错误。请更新您的问题并修复您的输出。 @VũBích
    • 感激不尽!这正是我想做的
    猜你喜欢
    • 1970-01-01
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多