web-dev-qa-db-ja.com

C#で2つの辞書を比較する方法

私は2つの汎用辞書を持っていますが、両方とも同じキーを持っていますが、値は異なっていてもかまいません。

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

Barcode   1234566666
Price     20.00


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

Barcode   1234566666
Price     40.00


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

Price     40

誰でも私にこれを行うための最良のアルゴリズムを教えてもらえますか?私はアルゴリズムを書きましたが、ループがたくさんあります。短くて効率的なアイデアを探しています。また、LINQクエリ式またはLINQラムダ式を使用したソリューションも必要です。 C#で.Net Framework 3.5を使用しています。 Except()メソッドについて何かを見つけました。しかし残念ながら、その方法で何が起こっているのか理解できませんでした。提案されたアルゴリズムを説明する人がいるとすばらしい。

21
Thabo

キーが同じであることをすでに確認している場合は、次を使用できます。

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

説明すると、これは:

  • dict2のキー/値ペアを反復処理します
  • 各エントリについて、dict1の値を検索し、2つの値が同じであるエントリを除外します
  • dict1に現れるように各ペアからキーと値を取得することにより、残りのエントリ(つまり、dict2値が異なるエントリ)から辞書を作成します。

KeyValuePair<TKey, TValue> -itmightの等式に依存することを回避することに注意してください。個人的に私はこれをより明確にします。 (辞書キーにカスタム等値比較子を使用している場合にも機能しますが、ToDictionaryにも渡す必要があります。)

33
Jon Skeet

試してください:

dictionary1.OrderBy(kvp => kvp.Key)
           .SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
24
Royi Namir

違いを確認するには、

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

次のコードは、すべての異なる値を返します

dic1.Except(dic2) 
12

あなたは両方の辞書が同じキーを持っていると述べたので、この仮定が正しければ、あなたは何も派手なものを必要としません:

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

それとも私はあなたの問題を誤解していますか?

11
carlosfigueira

それらをキーで結合し、両方の値を選択できるはずです。次に、値が同じか異なるかに基づいてフィルタリングできます。最後に、キーと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 );
            }
      }
  }
2
tvanfosson

両方の辞書に同じキーがあると仮定すると、最も簡単な方法は

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

[〜#〜] edit [〜#〜]

a.Except(b)b.Except(a)とは異なる結果を与えることに注意してください。

_a.Except(b): Price     20
b.Except(a): Price     40
_
2
Adi Lester
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);
2
Saeed Amiri

オブジェクトをディクショナリに変換してから、セットコンセプトに従ってそれらを減算すると、結果アイテムは同一である場合に空になります。

 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.

コードのソース

0
Mohamed.Abdo