2012-04-11 69 views
5

我有兩個排序的字典兩者同類型簽名的壓縮和解/合併兩個排序列表

SortedDictionary<decimal, long> A 
SortedDictionary<decimal, long> B 

我要合併兩個列表,其中的關鍵是一樣的,這樣就產生一個新的列表像

SortedDictionary<decimal, KeyValuePair<long,long>> 
or 
SortedDictionary<decimal, List<long>> 

這可能不是approacing情況的最好辦法,但可能有人給我擡起頭,就如何做到這一點還是一個更好的方式來處理它。

+0

爲什麼第二個是KeyValuePair?不應該只是一個列表? – Tigran 2012-04-11 12:35:45

+0

列表將工作。將其添加到 – Abstract 2012-04-11 12:37:37

+3

試圖確保我理解您的內容 - 是否希望初始字典中只有*一個*的元素出現在輸出字典中,或者只有*鍵出現在兩個字典中? @Tigran--希望這會清除一切 – 2012-04-11 13:11:30

回答

5

這是我的本錢:

SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>> 
(
    A.Union(B) 
    .ToLookup(x => x.Key, x => x.Value) 
    .ToDictionary(x => x.Key, x => new List<long>(x)) 
); 

編輯:上述解決方案選擇不包含在這兩個集合中的關鍵字。這應該選擇其中鍵是一樣的:

SortedDictionary<decimal, List<long>> merged = new SortedDictionary<decimal, List<long>> 
(
    A.Where(x=>B.ContainsKey(x.Key)) 
    .ToDictionary(x => x.Key, x => new List<long>(){x.Value, B[x.Key]}) 
); 
+0

oooo我認爲這是一個非常乾淨的方式接近它!我喜歡.ToLookup()調用比GroupBy更好 - 使我更容易理解 – 2012-04-11 13:17:43

+0

OP應該不會進一步回答:) – NSGaga 2012-04-11 13:23:51

+0

「我想合併兩個列表,其中鍵是相同的。」您的答案包括不在兩個詞典中的鍵。 – jason 2012-04-11 13:26:52

0

這樣做的另一個LINQ的方式,我認爲抓住了一套操作方面的意圖更好:

SortedDictionary<decimal, long> a = new SortedDictionary<decimal, long>(); 
SortedDictionary<decimal, long> b = new SortedDictionary<decimal, long>(); 

a.Add(0, 10); 
a.Add(1, 10); 
a.Add(2, 100); 
a.Add(100, 1); 

b.Add(0, 4); 
b.Add(4, 4); 
b.Add(2, 10); 

var result = a.Union(b) 
    .GroupBy(x => x.Key) 
    .ToDictionary(x => x.Key, x => x.Select(y => (long)y.Value).ToList()); 
+0

這不會添加兩個字典中沒有**相同**鍵的元素。 – Tigran 2012-04-11 13:04:49

+0

請注意,我不知道是否需要輸出爲「SortedDictionary」。如果是這樣,這不難解決。 – 2012-04-11 13:05:04

+0

@Tigran - OP聲明'我想合併兩個關鍵字相同的列表'。我認爲這意味着一個聯盟 – 2012-04-11 13:07:28

0

嘗試是這樣的,它並不容易:

Dictionary<decimal, long> dic1 = new Dictionary<decimal, long>{ {3,23}, {2,3}, {5,4}, {6,8}}; 
    Dictionary<decimal, long> dic2 = new Dictionary<decimal, long>{ {3,2}, {2,5}, {5,14}, {12,2}}; 


    //recover shared keys (the keys that are present in both dictionaries) 
    var sharedKeys = dic1.Select(dic => dic.Key).Intersect(dic2.Select(d2=>d2.Key)); 
    sharedKeys.Dump(); 

    //add to the fìnal dictionary 
    var final = new Dictionary<decimal, List<long>>(); 
    foreach(var shk in sharedKeys) { 

     if(!final.ContainsKey(shk)) 
      final[shk] = new List<long>(); 

     final[shk].Add(dic1[shk]); 
     final[shk].Add(dic2[shk]); 
    } 

**EDIT** 
//Skip below part if you need only keys present on both dictionaries. 
///----------------------------------------------------------------- 

    //get unique keys present in Dic1 and add 
    var nonsharedkeys1 = dic1.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k)); 
    foreach(var nshk in nonsharedkeys1) { 

     final[nshk] = new List<long>();    
     final[nshk].Add(dic1[nshk]);   
    } 

    //get unique keys present in Dic2 and add 
    var nonsharedkeys2 = dic2.Select(d=>d.Key).Where(k=>!sharedKeys.Contains(k)); 
    foreach(var nshk in nonsharedkeys2) { 

     final[nshk] = new List<long>();    
     final[nshk].Add(dic2[nshk]);   
    } 

應該工作爲你。

0

你可以簡單地使用LINQ做到這一點:

var query = from a in A 
      join b in B 
       on a.Key equals b.Key 
      select new { 
       Key = a.Key, 
       Value = Tuple.Create(a.Value, b.Value) 
      }; 
var merged = new SortedDictionary<decimal, Tuple<long, long>>(
       query.ToDictionary(x => x.Key, x => x.Value) 
      ); 

我想你應該在合併後的字典使用Tuple<long, long>爲您TValue

+0

你的結果與我用相同的數據運行時得到的擴展語法不同。你們產生:{{0,{10,4},{2,{100,10}}}。礦產生:{{0,{10,4}},{1,{10}},{2,{100,10}},{100,{1}},{4,{4}}}我的文章中的示例條目) – 2012-04-11 13:16:57

+0

不適用於'list1:{{1,1} {2,2}}和'list2:{{2,2} {3,3}} – 2012-04-11 13:17:09

+0

@LB:我們清楚地理解不同的要求。在你的例子中,我的產生'{2,(2,2)}'。這似乎符合「我想合併兩個關鍵字相同的列表」的要求。請告訴我你是如何理解它的。我們中只有一個可以是對的。 – jason 2012-04-11 13:20:08

0

你可以「濫用」 ConcatAggregate這樣的:

var A = new SortedDictionary<decimal,long>(); 
var B = new SortedDictionary<decimal,long>(); 

A.Add(1, 11); 
A.Add(2, 22); 
A.Add(3, 33); 

B.Add(2, 222); 
B.Add(3, 333); 
B.Add(4, 444); 

var C = A.Concat(B).Aggregate(
    new SortedDictionary<decimal, List<long>>(), 
    (result, pair) => { 
     List<long> val; 
     if (result.TryGetValue(pair.Key, out val)) 
      val.Add(pair.Value); 
     else 
      result.Add(pair.Key, new[] { pair.Value }.ToList()); 
     return result; 
    } 
); 

foreach (var x in C) 
    Console.WriteLine(
     string.Format(
      "{0}:\t{1}", 
      x.Key, 
      string.Join(", ", x.Value) 
     ) 
    ); 

輸出結果:

1:  11 
2:  22, 222 
3:  33, 333 
4:  444 

這幾乎是一樣的,如果你寫了一個「正常」的foreach並會實際上可以在任何IEnumerable<KeyValuePair<decimal, long>>(而不僅僅是SortedDictionary<decimal, long>)上工作,並且如果需要,很容易擴展到兩個以上的輸入集合。

不幸的是,它也完全忽視了這樣一個事實,即輸入SortedDictionary很好地被排序,因此性能不是最優的。爲了獲得最佳性能,您必須爲每個輸入的已排序詞典提供線性前進單獨IEnumerator,同時不斷比較基本元素 - 您可以完全避免TryGetValue這種方式...