2017-08-15 33 views
3

我的第一个数据收集是这样的:如何连接两个字典收藏LINQ查询

IEnumerable<Dictionary<string, object>> firstSourceData; 

的项目是这样的:

new Dictionary<string, object> 
{ 
    ["id"] = 1, 
    ["name"] = "some", 
    ["age"] = 30 
} 

我的第二个数据是另一个字典集合:

IEnumerable<Dictionary<string, object>> secondSourceData; 

项目如下:

new Dictionary<string, object> 
{ 
    ["id"] = 1, 
    ["sales"] = 58, 
    ["age"] = 30 
} 

这两个数据来自不同的来源,我将创建一个不包含重复值的单个字典集合。只有Id键才是Dictianaries的标准,其他属性可能会发生变化。

IEnumerable<Dictionary<string, object>> joined; 

new Dictionary<string, object> 
{ 
    ["id"] = 1, 
    ["sales"] = 58, 
    ["name"] = "some", 
    ["age"] = 30 
}, 

我该怎么用LINQ lambda表达式来做这件事? (而且是没有任何问题,如果源长度差)

+0

所以你要加入b y id? –

+0

是按ID加入的。 – barteloma

+0

@Bookmaster:每个字典都包含id-key? –

回答

1

这是你在找什么做:

  • 合并词典的两个集合。
  • 按“id”键值分组项目。
  • 对于每个组你有多个字典,所以使用SelectMany来平整,然后GroupBy上的关键。现在您可以重新创建字典 - ToDictionary。注意你可能有自己重复的键,这就是为什么嵌套GroupBy和值选择你想要的。在这里,我只是用FirstOrDefault

所以:

var result = firstSourceData.Concat(secondSourceData) 
       .GroupBy(item => item["id"]) 
       .Select(group => group.SelectMany(item => item) 
             .GroupBy(item => item.Key) 
             .ToDictionary(key => key.Key, 
                value => value.FirstOrDefault().Value)); 

这是结果:

new Dictionary<string, object> 
{ 
    ["id"] = 1, 
    ["sales"] = 58, 
    ["name"] = "some", 
    ["age"] = 30 
}, 
new Dictionary<string, object> 
{ 
    ["id"] = 2, 
    ["sales"] = 58, 
    ["age"] = 30 
} 

对于这个测试案例:

var firstSourceData = new List<Dictionary<string, object>> 
{ 
    new Dictionary<string, object> 
    { 
     ["id"] = 1, 
     ["sales"] = 58, 
     ["age"] = 30 
    }, 
    new Dictionary<string, object> 
    { 
     ["id"] = 2, 
     ["sales"] = 58, 
     ["age"] = 30 
    } 
}; 

var secondSourceData = new List<Dictionary<string, object>> 
{ 
    new Dictionary<string, object> 
    { 
     ["id"] = 1, 
     ["name"] = "some", 
     ["age"] = 30 
    } 
}; 
+1

'.ToDictionary(key => key.Key,value => value.FirstOrDefault()。Value)'为我工作。谢谢 – barteloma

+0

@bookmarker - ops true :)否则值是'KeyValuePair '。更正 –

+0

我们可以做到这一点,而不使用身份证密钥。你可以加入所有,无重复?所以所有的属性都会插入到新的字典中。 – barteloma

-1

你可以做联盟:

Dictionary<string,object> dict1 = new Dictionary<string, object>(); 
     dict1.Add("id", 1); 
     dict1.Add("name", "Some"); 
     dict1.Add("age", 30); 

     Dictionary<string, object> dict2 = new Dictionary<string, object>(); 
     dict2.Add("id", 1); 
     dict2.Add("sales", 58); 
     dict2.Add("age", 30); 

     Dictionary<string, object> dict3 = new Dictionary<string, object>(); 
     dict3 = dict1.Union(dict2).ToDictionary(c => c.Key, c => c.Value); 

结果值:

[0] = {[id, 1]} 
[1] = {[name, Some]} 
[2] = {[age, 30]} 
[3] = {[sales, 58]} 
+2

不是'字典<字符串,对象>'它的集合'IEnumerabl <字典<字符串,对象>>' – barteloma

-1

concat

IEnumerable<Dictionary<string, object>> joined; 

joined= firstSSourceData.Concat(secondSourceData.Where(a => !firstSSourceData.ContainsKey(a.Key))); 
0

做到这一点你可以这样使用Join

from dict1 in firstSourceData 
join dict2 in secondSourceData 
on dict1["id"] equals dict2["id"] 
select dict1.Concat(          //concatenates 2 dictionaries together 
      dict2.Where(kv => !dict1.ContainsKey(kv.Key)) //chooses non-repeating keys 
     ).ToDictionary(kv => kv.Key, kv => kv.Value)  //gets a new dictionary from that 

如果源的长度不同join只会选择这些字典,其中id s在第一个来源。如果你想获得的所有id S,你无论有两个来源的数据,你可以使用DefaultIfEmpty

from dict1 in firstSourceData 
join tempDict2 in secondSourceData 
on dict1["id"] equals tempDict2["id"] into joined 
from dict2 in joined.DefaultIfEmpty(new Dictionary<string, object>()) //make a new dictionary if there's none 
select dict1.Concat(
      dict2.Where(kv => !dict1.ContainsKey(kv.Key)) 
     ).ToDictionary(kv => kv.Key, kv => kv.Value) 

如果你想从字典都不管id s请参阅this问题。

+0

邮编不通过Id,但索引加入。 OP想要一个扁平版本,其中集合包含每个id的字典以及属于该id的所有收集的属性,并在所有字典中找到。 –

+0

好吧,op没有提到这样的东西:) –

+0

但你做出了从未提及过的假设,OP刚才说过他希望每个id都有一个字典,它也包含所有其他“属性”(键值对)属于该ID并且从两个序列中的所有字典中收集。唯一静态的是每个字典都包含id-key。 –