如何在C#中比较两个字典

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9547351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 07:50:17  来源:igfitidea点击:

How to compare two Dictionaries in C#

c#algorithmdictionarydata-structurescollections

提问by Thabo

I have two Generic Dictionaries.Both have same keys.But values can be different.I want to compare 2nd dictionary with 1st dictionary .If there are differences between values i want to store those values in separate dictionary.

我有两个通用字典。两者都有相同的键。但值可能不同。我想将第二个字典与第一个字典进行比较。如果值之间存在差异,我想将这些值存储在单独的字典中。

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

Barcode   1234566666
Price     20.00


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

Barcode   1234566666
Price     40.00


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

Price     40

Can Anyone give me a best algorithm to do this.I wrote an algorithm but it have lot of loops. I am seeking a short and efficient idea.Also like a solution by using LINQ query expression or LINQ lamda expression. I am using .Net Framework 3.5 with C#. I found some thing about Except() method. But Unfortunately i couldn't understand what is happening on that method. It is great if any one explains the suggested algorithm.

谁能给我一个最好的算法来做到这一点。我写了一个算法,但它有很多循环。我正在寻求一个简短而有效的想法。也喜欢使用 LINQ 查询表达式或 LINQ lamda 表达式的解决方案。我在 C# 中使用 .Net Framework 3.5。我发现了一些关于 Except() 方法的东西。但不幸的是,我无法理解该方法发生了什么。如果有人解释了建议的算法,那就太好了。

采纳答案by Jon Skeet

If you've already checked that the keys are the same, you can just use:

如果您已经检查过密钥是否相同,则可以使用:

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

To explain, this will:

为了解释,这将:

  • Iterate over the key/value pairs in dict2
  • For each entry, look up the value in dict1and filter out any entries where the two values are the same
  • Form a dictionary from the remaining entries (i.e. the ones where the dict1value is different) by taking the key and value from each pair just as they appear in dict2.
  • 迭代中的键/值对 dict2
  • 对于每个条目,查找值dict1并过滤掉两个值相同的任何条目
  • 形成从剩余的条目字典(即的那些,其中dict1值是不同的)通过取来自每对就像它们出现在键和值dict2

Note that this avoids relying on the equality of KeyValuePair<TKey, TValue>- it mightbe okay to rely on that, but personally I find this clearer. (It will also work when you're using a custom equality comparer for the dictionary keys - although you'd need to pass that to ToDictionary, too.)

请注意,这避免了依赖于的相等性KeyValuePair<TKey, TValue>-依赖于它可能没问题,但我个人觉得这更清楚。(当您对字典键使用自定义相等比较器时,它也可以工作 - 尽管您也需要将其传递给ToDictionary。)

回答by carlosfigueira

You mentioned that both dictionaries have the same keys, so if this assumption is correct, you don't need anything fancy:

你提到两个字典有相同的键,所以如果这个假设是正确的,你不需要任何花哨的东西:

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

Or am I misunderstanding your problem?

还是我误解了你的问题?

回答by tvanfosson

You should be able to join them on their keys and select both values. Then you can filter based on whether the values are the same or different. Finally, you can convert the collection to a dictionary with the keys and second values.

您应该能够在它们的键上加入它们并选择两个值。然后您可以根据值是相同还是不同进行过滤。最后,您可以将集合转换为带有键和第二个值的字典。

  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 );

Using a loop shouldn't be too bad either. I suspect that they would have similar performance characteristics.

使用循环也不应该太糟糕。我怀疑它们会具有相似的性能特征。

  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 );
            }
      }
  }

回答by Royi Namir

try :

尝试 :

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

回答by Adi Lester

Assuming both dictionaries have the same keys, the simplest way is

假设两个字典有相同的键,最简单的方法是

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

EDIT

编辑

Note that a.Except(b)gives a different result from b.Except(a):

请注意,它a.Except(b)给出了不同的结果b.Except(a)

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

回答by Saeed Amiri

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

Edit:If you sure all keys are same you can do:

编辑:如果您确定所有密钥都相同,您可以执行以下操作:

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

回答by Chamika Sandamal

to check any difference,

检查任何差异,

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

following code return all the different values

以下代码返回所有不同的值

dic1.Except(dic2) 

回答by Mohamed.Abdo

converting the object to dictionary then following set concept subtract them, result items should be empty in case they are identically.

将对象转换为字典,然后按照集合概念减去它们,如果它们相同,结果项应该为空。

 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

代码来源

回答by TheConstructor

In recent C# versions you can try

在最近的 C# 版本中,您可以尝试

        public static Dictionary<TK, TV> ValueDiff<TK, TV>(this Dictionary<TK, TV> dictionary,
            Dictionary<TK, TV> otherDictionary)
        {
            IEnumerable<(TK key, TV otherValue)> DiffKey(KeyValuePair<TK, TV> kv)
            {
                var otherValue = otherDictionary[kv.Key];
                if (!Equals(kv.Value, otherValue))
                {
                    yield return (kv.Key, otherValue);
                }
            }

            return dictionary.SelectMany(DiffKey)
                .ToDictionary(t => t.key, t => t.otherValue, dictionary.Comparer);
        }

I am not sure that SelectManyis always the fastest solution, but it is one way to only select the relevant items and generate the resulting entries in the same step. Sadly C# does not support yield returnin lambdas and while I could have constructed single or no item collections, I choose to use an inner function.

我不确定这SelectMany总是最快的解决方案,但它是仅选择相关项目并在同一步骤中生成结果条目的一种方法。遗憾的是,C# 不支持yield returnlambda,虽然我可以构建单个或不构建项目集合,但我选择使用内部函数。

Oh and as you say that the keys are the same, it may be possible to order them. Then you could use Zip

哦,正如你所说的,钥匙是一样的,也许可以订购它们。然后你可以使用Zip

        public static Dictionary<TK, TV> ValueDiff<TK, TV>(this Dictionary<TK, TV> dictionary,
            Dictionary<TK, TV> otherDictionary)
        {
            return dictionary.OrderBy(kv => kv.Key)
                .Zip(otherDictionary.OrderBy(kv => kv.Key))
                .Where(p => !Equals(p.First.Value, p.Second.Value))
                .ToDictionary(p => p.Second.Key, p => p.Second.Value, dictionary.Comparer);
        }

Personally I would tend not to use Linq, but a simple foreachlike carlosfigueira and vanfosson:

就我个人而言,我倾向于不使用 Linq,而是使用foreach像 carlosfigueira 和 vanfosson 这样的简单:

        public static Dictionary<TK, TV> ValueDiff2<TK, TV>(this Dictionary<TK, TV> dictionary,
            Dictionary<TK, TV> otherDictionary)
        {
            var result = new Dictionary<TK, TV>(dictionary.Count, dictionary.Comparer);
            foreach (var (key, value) in dictionary)
            {
                var otherValue = otherDictionary[key];
                if (!Equals(value, otherValue))
                {
                    result.Add(key, otherValue);
                }
            }

            return result;
        }

回答by raj

 using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text.RegularExpressions;
 namespace algorithms
{
    public class Program
    {
        public static void Main(string[] args)
        {
            callAnnagrams();
            //callArrayChunkingStr();
            //callFizzBussStr();
            //callMaxChars();
            //callRevNumber();
            //string value = "Acheck";
            //Console.WriteLine("value" + value.IsStartWithA());
            //callPalindromeStringMethods();
            //callRevStringMethods();

        }
        public static void callRevStringMethods()
        {
            Console.WriteLine("Hello World!");
            string revString = RevStrings.RevString("You cannot convert an array of strings to an array of characters by just calling a method like ToCharArray");
            Console.WriteLine("reverse string " + revString);

            string revString2 = RevStrings.RevString2("You cannot convert an array of strings to an array of characters by just calling a method like ToCharArray");
            Console.WriteLine("reverse string2 " + revString2);

            string revString3 = RevStrings.RevString3("You cannot convert an array of strings to an array of characters by just calling a method like ToCharArray");
            Console.WriteLine("reverse string3 " + revString3);

            string revString4 = RevStrings.RevString4("You cannot convert an array of strings to an array of characters by just calling a method like ToCharArray");
            Console.WriteLine("reverse string4 " + revString4);

        }
        public static void callPalindromeStringMethods()
        {
            Console.WriteLine("Hello World!");
            bool blPalindrome = Palindrome.PalindromeString("abba");
            Console.WriteLine("string is Palindrome" + blPalindrome);
            bool blPalindrome1 = Palindrome.PalindromeString("dfasdf");
            Console.WriteLine("string is Palindrome" + blPalindrome1);
        }

        public static void callRevNumber()
        {

            Console.WriteLine("reversed -1123.567 value" + RevNumbers.RevNumber3(-1123.567));
            Console.WriteLine("reversed 1123.567 value" + RevNumbers.RevNumber3(1123.567));
            Console.WriteLine("reversed -1123.567" + RevNumbers.RevNumber2(-1123.567));
            Console.WriteLine("reversed 234 value" + RevNumbers.RevNumber(234));
            Console.WriteLine("reversed -234 value" + RevNumbers.RevNumber(-234));           

        }

        public static void callMaxChars()
        {
            //MaxChar.MaxCharsWithASCII("rwersfsdfsdfsdf");
            //MaxChar.MaxCharsWithASCII("testtestttettssssssssssstest");
            MaxChar.MaxCharsWithDictionary("testtestttettssssssssssstest");

        }
        public static void callFizzBussStr()
        {
            FizzBuss.FizzBussStr();
        }
        public static void callArrayChunkingStr()
        {
            int[] numArray = new int[] { 1, 3, 5, 6, 7, 8, 8,9 };
            ArrayList anum=new ArrayList { 'a','b','c','d','e' };
            ArrayChunking.ArrayChunkingStr2(anum, 3);
            Console.WriteLine();
            anum = new ArrayList { 1, 2, 3, 4, 5, 6, 7, 8,9 };
            ArrayChunking.ArrayChunkingStr2(anum, 2);
            Console.WriteLine();
            numArray = new int[] { 1, 2, 3, 4, 5 };
            ArrayChunking.ArrayChunkingStr(numArray, 10);
        }
        public static void callAnnagrams()
        {
            Annagram.Annagrams("this is a valid string ", "sa i hits daliv gnirts");
            Annagram.Annagrams("this is a valid string ", "ssdfasdfad dsfasdf453 $ ,fgdaliv gnirts");
            Annagram.Annagrams("string $ ONE ,", "snigtr # neo");

        }
    }
    public static class StringMethods
    {
        public static bool IsStartWithA(this string s)
        {
            return s.StartsWith('A');
        }
    }
    public class RevStrings
    {
        public static string RevString(string str)
        {
            var charArry = str.ToCharArray();
            Array.Reverse(charArry);
            return new string(charArry);
        }
        public static string RevString2(string str)
        {
            string revString = "";
            foreach( char c in str)
            {
                revString = c + revString;
            }

            return revString;
        }

        //no change to the order of the words
        public static string RevString3(string str)
        {
            string[] strArray = str.Split(' ');

            string revString = "";
            foreach (string s in strArray)
            {
                var charArray = s.ToCharArray();
                Array.Reverse(charArray);

                string reString = (strArray.Length > 1) ? new string(charArray) +" " : new string(charArray) + string.Empty;
                revString +=  reString;

            }

            return revString;
        }
        public static string RevString4(string str)
        {
            string[] strArray = str.Split(' ');

            string revString = "";
            foreach (string s in strArray)
            {
                string revWord = "";
                foreach(char c in s)
                {
                    revWord = c + revWord;
                }
                revString += revWord + " ";
            }

            return revString;
        }

    }

    public class Palindrome
    {
        public static bool PalindromeString(string str)
        {
            if (RevStrings.RevString3(str).ToUpper() == str.ToUpper())
                return true;
            else
                return false;
        }
    }

    public class RevNumbers
    {
        public static int RevNumber(int number)
        {
            string revStringNumber = RevStrings.RevString2(number.ToString().Replace("-", ""));

            Int32 num = Int32.Parse(revStringNumber) * Math.Sign(number);
            return num;
        }
        public static double RevNumber2(double number)
        {         
            string revStringNumber = RevStrings.RevString2(number.ToString().Replace("-", ""));
            double num = Convert.ToDouble(revStringNumber) * Math.Sign(number); 

            return num;
        }
        public static double RevNumber3(double number)
        {
            string[] strArray = number.ToString().Replace("-", "").Split('.');
            string revString = "";
            int i = 0;

            foreach (string s in strArray)
            {
                var charArray = s.ToCharArray();
                Array.Reverse(charArray);
                string reString = new string(charArray);
                if (i + 1 < strArray.Length && strArray[i].Length > 0)
                    revString += reString + ".";
                else
                    revString += reString;
                i++;
            }
            double num = Convert.ToDouble(revString.ToString().Replace("-", "")) * Math.Sign(number);

            return num;


        }


    }

    public class MaxChar
    {
        public static void MaxCharsWithASCII(string str)
        {
            int i = 0, l, max;
            int ascii;
            l = str.Length;
            int[] ch_freq = new int[255];

            for (i = 0; i < 255; i++)
            {
                ch_freq[i] = 0;
            }

            i = 0;
            while(i<l)
            {
                ascii = (int)str[i];
                ch_freq[ascii] += 1;

                i++;
            }

            max = 0;
            for(i=0; i<255; i++)
            {
                if (i != 32)
                {
                    if (ch_freq[i] > ch_freq[max])
                        max = i;
                }
            }
            Console.Write("The Highest frequency of character '{0}' is appearing for number of times : {1} \n\n", (char)max, ch_freq[max]);

        }
        public static void MaxCharsWithDictionary(string str)
        {
            int i = 0, l, max;
            l = str.Length;
            Dictionary<int, int> char_freq = new Dictionary<int, int>();

            i = 0;
            while (i < l)
            {
                if(!(char_freq.ContainsKey((int)str[i])))
                    char_freq.Add((int)str[i], 1);               
                else
                    char_freq[(int)str[i]]= char_freq[str[i]]+1;
                i++;
            }

            max = 0;
            for (i = 0; i < char_freq.Count; i++)
            {

                    if (char_freq[str[i]] > char_freq[str[max]])
                        max = i;

            }
            Console.Write("The Highest frequency of character '{0}' is appearing for number of times : {1} \n\n",(char)str[max], char_freq[str[max]]);

        }
        public static Dictionary<int,int> MaxCharsWithReturnDictionary(string str)
        {
            int i = 0, l, max;
            l = str.Length;
            Dictionary<int, int> char_freq = new Dictionary<int, int>();

            i = 0;
            while (i < l)
            {
                if (!(char_freq.ContainsKey((int)str[i])))
                    char_freq.Add((int)str[i], 1);
                else
                    char_freq[(int)str[i]] = char_freq[str[i]] + 1;
                i++;
            }

            max = 0;
            for (i = 0; i < char_freq.Count; i++)
            {

                if (char_freq[str[i]] > char_freq[str[max]])
                    max = i;

            }
            return char_freq;
        }

    }

    public class FizzBuss
    {
        public static void FizzBussStr()
        {
            double num =Convert.ToDouble(Console.ReadLine());
            for (int i = 1; i <= num; i++)
            {
                if ((i % 3 == 0) && (i % 5 == 0)) //by both
                    Console.WriteLine("FizzBuzz");
                else if (i % 3 == 0)  //by 3
                    Console.WriteLine("Fizz");
                else if( i % 5 == 0) //by 5
                    Console.WriteLine("Buzz");
                else Console.WriteLine(i);
            }

        }
    }

    public class ArrayChunking
    {
        public static ArrayList ArrayChunkingStr2(ArrayList intArray, int chunk)
        {
            ArrayList arrList = new ArrayList();

            int len = intArray.Count;
            int div = len / chunk;
            int howManyChunks = (len % chunk) > 0 ? div + 1 : div;
            int chkInc = 0;
            for (int chkk = 0; chkk < howManyChunks; chkk++)
            {
                ArrayList arr = new ArrayList();
                for (int i = 0; i < chunk; i++)
                {
                    if ((i + chkInc) < len)
                    {
                        arr.Insert(i, intArray[i + chkInc]);
                    }
                }
                chkInc += chunk;
                arrList.Add(arr);
            }

            if (howManyChunks > 0)
            {
                //Console.Write("[");
                string disarr = "[";
                for (int j = 0; j < howManyChunks; j++)
                {
                    //Console.Write("[");
                    disarr += "[";

                    ArrayList x = (ArrayList)arrList[j];
                    string dis = "";
                    for (int i = 0; i < x.Count; i++)
                    {
                        dis += x[i].ToString() + ",";
                    }
                    dis = dis.TrimEnd(',');
                    disarr += dis + "],";
                    //Console.Write(disarr);
                }
                disarr = disarr.TrimEnd(',');
                //Console.Write("]");
                disarr += "]";
                Console.Write(disarr);
            }
            return arrList;
        }
        public static ArrayList ArrayChunkingStr(int[] intArray,int chunk)
        {
            ArrayList arrList = new ArrayList();

            int len = intArray.Length;
            int div = len / chunk;
            int howManyChunks = (len % chunk) > 0 ? div + 1: div;
            int chkInc = 0;
            for(int chkk=0; chkk < howManyChunks; chkk++)
            {
                ArrayList arr = new ArrayList();
                for (int i = 0; i < chunk; i++)
                {
                    if ((i + chkInc) < len)
                    {
                        arr.Insert(i,intArray[i + chkInc]);
                    }
                }
                chkInc += chunk;
                arrList.Add(arr);
            }

            if (howManyChunks > 0)
            {
                //Console.Write("[");
                string disarr = "[";
                for (int j = 0; j < howManyChunks; j++)
                {
                    //Console.Write("[");
                    disarr += "[";

                    ArrayList x = (ArrayList)arrList[j];
                    string dis = "";
                    for (int i = 0; i < x.Count; i++)
                    {
                        dis += x[i].ToString() + ",";
                    }
                    dis = dis.TrimEnd(',');
                    disarr += dis + "],";
                    //Console.Write(disarr);
                }
                disarr = disarr.TrimEnd(',');
                //Console.Write("]");
                disarr += "]";
                Console.Write(disarr);
            }
            return arrList;
        }
    }

    public class Annagram
    {
        public static bool Annagrams(string str1, string str2)
        {

            str1 = Regex.Replace(str1.ToLower(), "[^a-zA-Z0-9]+", "", RegexOptions.Compiled);
            str2 = Regex.Replace(str2.ToLower(), "[^a-zA-Z0-9]+", "", RegexOptions.Compiled);

            Dictionary<int, int> str1Dic = MaxChar.MaxCharsWithReturnDictionary(str1.ToLower());

            Dictionary<int, int> str2Dic = MaxChar.MaxCharsWithReturnDictionary(str2.ToLower());
            if (str1Dic.Count != str2Dic.Count)
            {
                Console.WriteLine("strings are not annagrams");
                return false;
            }
            else
            {
                if (!(str1Dic.Keys.All(str2Dic.ContainsKey)))
                {
                    Console.WriteLine("strings are not annagrams");
                    return false;
                }
                else
                {
                    var dict3 = str2Dic.Where(entry => str1Dic[entry.Key] != entry.Value)
                            .ToDictionary(entry => entry.Key, entry => entry.Value);
                    if (dict3.Count > 0)
                    {
                        Console.WriteLine("strings are not annagrams");
                        return false;
                    }
                    else
                    {
                        Console.WriteLine("strings are  annagrams");
                        return true;
                    }
                }


            }

        }
    }
}