2012-03-03 83 views
11

我有兩個通用詞典。兩者都有相同的鍵。但值可以不同。我想比較第二個詞典與第一個詞典。如果兩個值之間存在差異,我想將這些值存儲在單獨的字典。如何比較C#中的兩個詞典

1st Dictionary 
------------ 
key  Value 

Barcode 1234566666 
Price  20.00 


2nd Dictionary 
-------------- 
key  Value 

Barcode 1234566666 
Price  40.00 


3rd Dictionary 
-------------- 
key  Value 

Price  40 

任何一個可以給我一個最好的算法來幹這事寫一個算法,但它有很多loops.I的正在謀求高效短idea.Also等的溶液使用LINQ查詢表達式或LINQ lamda expression.I使用.Net Framework 3.5與C#。我發現了一些關於Except()方法的東西。但不幸的是,我不明白在該方法上發生了什麼。如果任何人解釋了建議的算法,這是非常好的。我總是喜歡學習:)。

謝謝 Thabo。

+0

你要什麼做的,如果一個關鍵出現在第一個字典而不是第二,反之亦然? – 2012-03-03 15:45:58

+0

不......實際的密鑰在名稱和計數上必須相同。我在使用iscontains()方法檢查算法之前進行檢查。預先感謝。 – Thabo 2012-03-03 15:52:08

回答

24

如果您已經檢查了密鑰是相同的,你可以使用:

var dict3 = dict2.Where(entry => dict1[entry.Key] != entry.Value) 
       .ToDictionary(entry => entry.Key, entry => entry.Value); 

講解,這將:

  • 遍歷的鍵/值對dict2
  • 對於每個條目,查找dict1中的值並過濾掉兩個值相同的任何條目
  • 形成詞典y從剩餘的條目(即dict1值不同的那些)通過從每一對中獲取密鑰和值,就像它們出現在dict2中那樣。

注意,這避免了依靠KeyValuePair<TKey, TValue>平等 - 這也許還好依靠這一點,但我個人認爲這更清晰。 (它也將在您使用自定義相等比較的字典鍵的作用 - 雖然你需要傳遞到ToDictionary,太)

6

你提到的兩個字典具有相同的密鑰,因此,如果這個假設是正確的,你不需要任何幻想:

 foreach (var key in d1.Keys) 
     { 
      if (!d1[key].Equals(d2[key])) 
      { 
       d3.Add(key, d2[key]); 
      } 
     } 

還是我誤解你的問題?

+0

你應該做'!d1 [key] .Equals(d2 [key])' – 2012-03-03 15:59:59

+0

ooops ...這很簡單..我可以這樣想,但有一點懷疑是這樣的表現。因爲我總是喜歡避免Order n操作。 – Thabo 2012-03-03 16:00:53

+1

你錯過了一個'!',因爲你想要不同的價值觀,而不是平等的價值觀。 – 2012-03-03 16:01:05

2

你應該可以在他們的鍵上加入他們並選擇兩個值。然後,您可以根據值是相同還是不同來過濾。最後,您可以使用鍵和第二個值將集合轉換爲字典。

var compared = first.Join(second, f => f.Key, s => s.Key, (f,s) => new { f.Key, FirstValue = f.Value, SecondValue = s.Value }) 
         .Where(j => j.FirstValue != j.SecondValue) 
         .ToDictionary(j => j.Key, j => j.SecondValue); 

使用循環也不應該太糟糕。我懷疑他們會有類似的表現特徵。

var compared = new Dictionary<string,object>(); 
    foreach (var kv in first) 
    { 
     object secondValue; 
     if (second.TryGetValue(kv.Key, out secondValue)) 
     { 
      if (!object.Equals(kv.Value, secondValue)) 
      { 
       compared.Add(kv.Key, secondValue); 
      } 
     } 
    } 
15

嘗試:

dictionary1.OrderBy(kvp => kvp.Key) 
      .SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key)) 
+1

這是比較值?這是返回一個集合或布爾值。 – Thabo 2012-03-03 16:04:17

+0

我嘗試了幾個不同的選項,字典鍵是一個字符串,這個似乎是迄今爲止最快的。 – 2017-04-03 20:44:15

2

假設兩個字典按鍵相同,最簡單的方法是

var result = a.Except(b).ToDictionary(x => x.Key, x => x.Value); 

編輯

注意a.Except(b)給出了不同的結果b.Except(a)

a.Except(b): Price  20 
b.Except(a): Price  40 
+0

如果這兩個字典中的密鑰順序不同,該怎麼辦? – Thabo 2012-03-03 15:55:30

+1

@Thabo是的。但請注意'a.Except(b)'與'b.Except(a)'有不同的結果。 – 2012-03-03 15:56:47

2
var diff1 = d1.Except(d2); 
var diff2 = d2.Except(d1); 
return diff1.Concat(diff2); 

編輯:如果你確保所有的按鍵都一樣,你可以這樣做:

var diff = d2.Where(x=>x.Value != d1[x.Key]).ToDictionary(x=>x.Key, x=>x.Value); 
+0

雖然這不會導致字典,但帶有'IEnumerable >' – 2012-03-03 16:04:01

+1

首先,我們不能有字典,但對於第二個,我會更新我的答案。 – 2012-03-03 16:18:13

5

檢查任何區別,

dic1.Count == dic2.Count && !dic1.Except(dic2).Any(); 

下面的代碼返回所有的不同的值

dic1.Except(dic2) 
+0

你能解釋這一點嗎?:) – Thabo 2012-03-03 16:14:18

+1

@Thabo:如果字典大小相同並且沒有第一個元素,也不在第二個字符,它們是等價的。第二行直接返回所有在第一個而不在第二個的元素 – 2012-03-03 16:18:39

0

轉換的對象字典,然後下面的一組概念相減如果結果相同,結果項目應該是空的。

public static IDictionary<string, object> ToDictionary(this object source) 
    { 
     var fields = source.GetType().GetFields(
      BindingFlags.GetField | 
      BindingFlags.Public | 
      BindingFlags.Instance).ToDictionary 
     (
      propInfo => propInfo.Name, 
      propInfo => propInfo.GetValue(source) ?? string.Empty 
     ); 

     var properties = source.GetType().GetProperties(
      BindingFlags.GetField | 
      BindingFlags.GetProperty | 
      BindingFlags.Public | 
      BindingFlags.Instance).ToDictionary 
     (
      propInfo => propInfo.Name, 
      propInfo => propInfo.GetValue(source, null) ?? string.Empty 
     ); 

     return fields.Concat(properties).ToDictionary(key => key.Key, value => value.Value); ; 
    } 
    public static bool EqualsByValue(this object source, object destination) 
    { 
     var firstDic = source.ToFlattenDictionary(); 
     var secondDic = destination.ToFlattenDictionary(); 
     if (firstDic.Count != secondDic.Count) 
      return false; 
     if (firstDic.Keys.Except(secondDic.Keys).Any()) 
      return false; 
     if (secondDic.Keys.Except(firstDic.Keys).Any()) 
      return false; 
     return firstDic.All(pair => 
      pair.Value.ToString().Equals(secondDic[pair.Key].ToString()) 
     ); 
    } 
    public static bool IsAnonymousType(this object instance) 
    { 

     if (instance == null) 
      return false; 

     return instance.GetType().Namespace == null; 
    } 
    public static IDictionary<string, object> ToFlattenDictionary(this object source, string parentPropertyKey = null, IDictionary<string, object> parentPropertyValue = null) 
    { 
     var propsDic = parentPropertyValue ?? new Dictionary<string, object>(); 
     foreach (var item in source.ToDictionary()) 
     { 
      var key = string.IsNullOrEmpty(parentPropertyKey) ? item.Key : $"{parentPropertyKey}.{item.Key}"; 
      if (item.Value.IsAnonymousType()) 
       return item.Value.ToFlattenDictionary(key, propsDic); 
      else 
       propsDic.Add(key, item.Value); 
     } 
     return propsDic; 
    } 
originalObj.EqualsByValue(messageBody); // will compare values. 

source of the code