【问题标题】:Easiest way to compare arrays in C#在 C# 中比较数组的最简单方法
【发布时间】:2011-03-15 01:10:02
【问题描述】:

在 Java 中,Arrays.equals() 允许轻松比较两个基本数组的内容(重载可用于所有基本类型)。

C#中有这样的东西吗?在 C# 中比较两个数组的内容有什么“神奇”的方法吗?

【问题讨论】:

  • 对于阅读本文的每个人,请记住,接受的答案是使用 SequenceEqual。 SequenceEqual 不仅会检查它们是否包含相同的数据,还会检查它们是否以相同的顺序包含相同的数据

标签: c# .net arrays compare


【解决方案1】:

您可以使用Enumerable.SequenceEqual。这适用于任何IEnumerable<T>,而不仅仅是数组。

【讨论】:

  • 这只有在它们的顺序相同时才有效
  • SequenceEqual 在性能方面可能不是一个好的选择,因为如果它们仅在长度上有所不同,它的当前实现可能会完全枚举其来源之一。对于数组,我们可以先检查Length是否相等,以避免枚举不同长度的数组最终产生false
  • @Frédéric,事实上SequenceEqual 将首先比较长度,如果两个可枚举都实现ICollection,请参阅github.com/dotnet/runtime/blob/main/src/libraries/System.Linq/…
  • @quinmars,这个答案是关于.Net Framework的,.Net Core在2010年不存在。相关代码是here。知道这一点在 .Net Core 中发生了变化仍然是一件好事。但对于 .Net 框架来说,它仍然适用。
  • 为什么这不是这里唯一推荐的答案,只是好奇
【解决方案2】:

LINQ 中使用Enumerable.SequenceEqual

int[] arr1 = new int[] { 1,2,3};
int[] arr2 = new int[] { 3,2,1 };

Console.WriteLine(arr1.SequenceEqual(arr2)); // false
Console.WriteLine(arr1.Reverse().SequenceEqual(arr2)); // true

【讨论】:

  • 请记住,这会抛出空参数,因此请确保不要假设 new int[] {1}.SequenceEquals(null) == false
【解决方案3】:

对于数组(和元组),您还可以使用 .NET 4.0 中的新接口:IStructuralComparableIStructuralEquatable。使用它们,您不仅可以检查数组的相等性,还可以比较它们。

static class StructuralExtensions
{
    public static bool StructuralEquals<T>(this T a, T b)
        where T : IStructuralEquatable
    {
        return a.Equals(b, StructuralComparisons.StructuralEqualityComparer);
    }

    public static int StructuralCompare<T>(this T a, T b)
        where T : IStructuralComparable
    {
        return a.CompareTo(b, StructuralComparisons.StructuralComparer);
    }
}

{
    var a = new[] { 1, 2, 3 };
    var b = new[] { 1, 2, 3 };
    Console.WriteLine(a.Equals(b)); // False
    Console.WriteLine(a.StructuralEquals(b)); // True
}
{
    var a = new[] { 1, 3, 3 };
    var b = new[] { 1, 2, 3 };
    Console.WriteLine(a.StructuralCompare(b)); // 1
}

【讨论】:

  • 在大值类型数组上,使用这些会影响性能,因为它们当前的实现会将每个值装箱以进行比较。
【解决方案4】:

对于 .NET 4.0 及更高版本,您可以使用 StructuralComparisons 类型比较数组或元组中的元素:

object[] a1 = { "string", 123, true };
object[] a2 = { "string", 123, true };

Console.WriteLine (a1 == a2);        // False (because arrays is reference types)
Console.WriteLine (a1.Equals (a2));  // False (because arrays is reference types)

IStructuralEquatable se1 = a1;
//Next returns True
Console.WriteLine (se1.Equals (a2, StructuralComparisons.StructuralEqualityComparer)); 

【讨论】:

    【解决方案5】:

    SequenceEqual 仅在两个条件或满足时才会返回 true。

    1. 它们包含相同的元素。
    2. 元素的顺序相同。

    如果您只想检查它们是否包含相同的元素而不管它们的顺序如何,并且您的问题属于类型

    values2 是否包含 values1 中包含的所有值?

    您可以使用 LINQ 扩展方法Enumerable.Except 然后检查结果是否有任何值。这是一个例子

    int[] values1 = { 1, 2, 3, 4 };
    int[] values2 = { 1, 2, 5 };
    var result = values1.Except(values2);
    if(result.Count()==0)
    {
       //They are the same
    }
    else
    {
        //They are different
    }
    

    而且通过使用它,您还可以自动获得不同的项目。一石两鸟。

    记住,如果你像这样执行你的代码

    var result = values2.Except(values1);
    

    你会得到不同的结果。

    就我而言,我有一个数组的本地副本,并想检查是否从原始数组中删除了任何内容,因此我使用此方法。

    【讨论】:

      【解决方案6】:

      如果您想优雅地处理null 输入,并忽略项目的顺序,请尝试以下解决方案:

      static class Extensions
      {
          public static bool ItemsEqual<TSource>(this TSource[] array1, TSource[] array2)
          {
              if (array1 == null && array2 == null)
                  return true;
              if (array1 == null || array2 == null)
                  return false;
              if (array1.Count() != array2.Count())
                  return false;
              return !array1.Except(array2).Any() && !array2.Except(array1).Any();
          }
      }
      

      测试代码如下:

      public static void Main()
      {
          int[] a1 = new int[] { 1, 2, 3 };
          int[] a2 = new int[] { 3, 2, 1 };
          int[] a3 = new int[] { 1, 3 };
          Console.WriteLine(a1.ItemsEqual(a2)); // Output: True.
          Console.WriteLine(a2.ItemsEqual(a3)); // Output: False.
          Console.WriteLine(a3.ItemsEqual(a2)); // Output: False.
         
          int[] a4 = new int[] { 1, 1 };
          int[] a5 = new int[] { 1, 2 };
          Console.WriteLine(a4.ItemsEqual(a5)); // Output: False 
          Console.WriteLine(a5.ItemsEqual(a4)); // Output: False 
          
          int[] a6 = null;
          int[] a7 = null;
          int[] a8 = new int[0];
      
          Console.WriteLine(a6.ItemsEqual(a7)); // Output: True. No Exception.
          Console.WriteLine(a8.ItemsEqual(a6)); // Output: False. No Exception.
          Console.WriteLine(a7.ItemsEqual(a8)); // Output: False. No Exception.
      }
      

      【讨论】:

        【解决方案7】:

        对于单元测试,您可以使用CollectionAssert.AreEqual 而不是Assert.AreEqual

        这可能是最简单的方法。

        【讨论】:

          【解决方案8】:

          对于某些应用程序可能会更好:

          string.Join(",", arr1) == string.Join(",", arr2)
          

          【讨论】:

          • 被低估的解决方案!这非常适合许多用例。
          • @Thomas 实际上他们投了几次票;)
          【解决方案9】:

          假设数组相等意味着两个数组在相同的索引处具有相同的元素,则有SequenceEqual answerIStructuralEquatable answer

          但两者都有缺点,性能方面。

          SequenceEqual 在 .Net Framework 中的实现在数组具有不同长度时不会快捷方式,因此它可以完全枚举其中一个,比较其中的每个元素。
          这就是说,根据 .Net 风格(如 .Net5),它可能是快捷方式,请参阅this comment。所以对于最新的 .Net 项目,SequenceEqual 应该是一个不错的选择。

          IStructuralEquatable 不是通用的,可能会导致每个比较值的装箱。此外,它使用起来不是很简单,并且已经需要编写一些帮助方法来隐藏它。

          在性能方面,使用类似的东西可能会更好:

          bool ArrayEquals<T>(T[] first, T[] second)
          {
              if (first == second)
                  return true;
              if (first == null || second == null)
                  return false;
              if (first.Length != second.Length)
                  return false;
              for (var i = 0; i < first.Length; i++)
              {
                  if (!first[i].Equals(second[i]))
                      return false;
              }
              return true;
          }
          

          当然,这也不是某种检查数组相等性的“神奇方式”。

          所以目前,不,.Net 中并没有真正等同于 Java Arrays.equals()

          【讨论】:

            【解决方案10】:

            此 LINQ 解决方案有效,但不确定它与 SequenceEquals 的性能相比如何。但它处理不同的数组长度,并且 .All 将在不遍历整个数组的情况下退出不相等的第一项。

            private static bool arraysEqual<T>(IList<T> arr1, IList<T> arr2)
                    =>
                        ReferenceEquals(arr1, arr2) || (
                            arr1 != null && arr2 != null &&
                            arr1.Count == arr2.Count &&
                            arr1.Select((a, i) => arr2[i].Equals(a)).All(i => i)
                        );
            

            【讨论】:

              【解决方案11】:

              逐元素比较?怎么样

              public void Linq78a()
              {
               int[] numbers1 = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
               int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
               bool bb = numbers.Zip(numbers1, (a, b) => (a == b)).Any(p => !p);
               if (!bb) Console.WriteLine("Lists are equal (bb)");
                 else Console.WriteLine("Lists are not equal (bb)");
              }
              

              将 (a==b) 条件替换为您想在 a 和 b 中比较的任何内容。

              (这结合了来自MSDN developer Linq samples 的两个示例)

              【讨论】:

              • 它不处理不同长度的数组(可能错误地产生true)和null数组(会崩溃)。
              【解决方案12】:

              我在视觉工作室做过这个,效果很好;用简短的这段代码逐个索引比较数组。

              private void compareButton_Click(object sender, EventArgs e)
                      {
                          int[] answer = { 1, 3, 4, 6, 8, 9, 5, 4, 0, 6 };
                          int[] exam = { 1, 2, 3, 6, 8, 9, 5, 4, 0, 7 };
              
                          int correctAnswers = 0;
                          int wrongAnswers = 0;
              
                          for (int index = 0; index < answer.Length; index++)
                          {
                              if (answer[index] == exam[index])
                              {
                                  correctAnswers += 1;
                              }
                              else
                              {
                                  wrongAnswers += 1;
                              }
                          }
              
                          outputLabel.Text = ("The matching numbers are " + correctAnswers +
                              "\n" + "The non matching numbers are " + wrongAnswers);
                      }
              

              输出将是;匹配的数字是 7 不匹配的数字是 3

              【讨论】:

              • 它不处理不同长度的数组(会崩溃),null 数组(也会崩溃),并且它做的不是 OP 要求的。他只要求知道相等,而不计算有多少项不同或匹配。
              【解决方案13】:

              你可以使用Enumerable.Intersect:

              int[] array1 = new int[] { 1, 2, 3, 4,5 },
                    array2 = new int[] {7,8};
              
              if (array1.Intersect(array2).Any())
                  Console.WriteLine("matched");
              else
                  Console.WriteLine("not matched");
              

              【讨论】:

              • 我认为这不是 OP 所要求的。这如何比较数组?它仅标识数组是否具有任何公共元素。这几乎不等同于 Java Arrays.equals()
              【解决方案14】:

              我想确定两个集合是否具有相同的内容,以任何顺序排列。这意味着,对于集合 A 中的每个元素,两个集合中具有该值的元素数量相等。我想考虑重复(所以 {1,2,2,3}{1,2,3,3} 不应被视为“相同”)。

              这是我想出的(注意 IsNullOrEmpty 是另一种静态扩展方法,如果可枚举为 null 或有 0 个元素,则返回 true):

                  public static bool HasSameContentsAs<T>(this IEnumerable<T> source, IEnumerable<T> target) 
                      where T : IComparable
                  {
                      //If our source is null or empty, then it's just a matter of whether or not the target is too
                      if (source.IsNullOrEmpty())
                          return target.IsNullOrEmpty();
              
                      //Otherwise, if the target is null/emtpy, they can't be equal
                      if (target.IsNullOrEmpty())
                          return false;
              
                      //Neither is null or empty, so we'll compare contents.  To account for multiples of 
                      //a given value (ex. 1,2,2,3 and 1,1,2,3 are not equal) we'll group the first set
                      foreach (var group in source.GroupBy(s => s))
                      {
                          //If there are a different number of elements in the target set, they don't match
                          if (target.Count(t => t.Equals(group.Key)) != group.Count())
                              return false;
                      }
              
                      //If we got this far, they have the same contents
                      return true;
                  }
              

              【讨论】:

                【解决方案15】:

                如果您不想比较订单,但您确实想比较每个项目的计数,包括处理空值,那么我已经为此编写了一个扩展方法。

                它给出了例如以下结果:

                new int?[]{  }.IgnoreOrderComparison(new int?{ });                            // true
                new int?[]{ 1 }.IgnoreOrderComparison(new int?{ });                           // false
                new int?[]{ }.IgnoreOrderComparison(new int?{ 1 });                           // false
                new int?[]{ 1 }.IgnoreOrderComparison(new int?{ 1 });                         // true
                new int?[]{ 1, 2 }.IgnoreOrderComparison(new int?{ 2, 1 });                   // true
                new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ 2, 1 });             // false
                new int?[]{ 1, 2, null }.IgnoreOrderComparison(new int?{ null, 2, 1 });       // true
                new int?[]{ 1, 2, null, null }.IgnoreOrderComparison(new int?{ null, 2, 1 }); // false
                new int?[]{ 2 }.IgnoreOrderComparison(new int?{ 2, 2 });                      // false
                new int?[]{ 2, 2 }.IgnoreOrderComparison(new int?{ 2, 2 });                   // true
                

                代码如下:

                public static class ArrayComparisonExtensions
                {
                    public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second) =>
                        IgnoreOrderComparison(first, second, EqualityComparer<TSource>.Default);
                
                    public static bool IgnoreOrderComparison<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer)
                    {
                        var a = ToDictionary(first, out var firstNullCount);
                        var b = ToDictionary(second, out var secondNullCount);
                
                        if (a.Count != b.Count)
                            return false;
                
                        if (firstNullCount != secondNullCount)
                            return false;
                
                        foreach (var item in a)
                        {
                            if (b.TryGetValue(item.Key, out var count) && item.Value == count)
                                continue;
                            return false;
                        }
                
                
                        return true;
                
                        Dictionary<TSource, int> ToDictionary(IEnumerable<TSource> items, out int nullCount)
                        {
                            nullCount = 0;
                            var result = new Dictionary<TSource, int>(comparer);
                            foreach (var item in items)
                            {
                                if (item is null)
                                    nullCount++;
                                else if (result.TryGetValue(item, out var count))
                                    result[item] = count + 1;
                                else
                                    result[item] = 1;
                            }
                
                            return result;
                        }
                    }
                }
                

                它只对每个可枚举项进行一次枚举,但它确实为每个可枚举项创建了一个字典,并且也对它们进行了一次迭代。我会对改进这一点的方法感兴趣。

                【讨论】:

                  【解决方案16】:

                  检查this thread 的答案,它将其中一个数组转换为HashSet,并使用SetEquals 与另一个数组进行比较。

                  【讨论】:

                    【解决方案17】:

                    如果需要比较顺序不同的数组,也可以使用array1.ToList().All(x =&gt; array2.Contains(x))

                    【讨论】:

                    • 您好,欢迎来到 StackOverflow!此答案不会彻底比较数组,因为如果 array1 包含 [1],并且 array2 包含 [1,2,3,4,5],它将返回 true。关于这个问题的其他与使用交叉点相关的答案回答得更彻底。
                    【解决方案18】:
                            int[] a = { 2, 1, 3, 4, 5, 2 };
                    
                            int[] b = { 2, 1, 3, 4, 5, 2 };
                    
                            bool ans = true;
                    
                            if(a.Length != b.Length)
                            {
                                ans = false;
                            }
                            else
                            {
                                for (int i = 0; i < a.Length; i++)
                                {
                                    if( a[i] != b[i])
                                    {
                                        ans = false;
                                    }
                                }
                            }
                    
                            string str = "";
                    
                            if(ans == true)
                            {
                                str = "Two Arrays are Equal";
                            }
                    
                            if (ans == false)
                            {
                                str = "Two Arrays are not Equal";
                            }
                    
                           //--------------Or You can write One line of Code-------------
                    
                            var ArrayEquals = a.SequenceEqual(b);   // returns true
                    

                    【讨论】:

                    • 那不是最理想的。您应该停止对第一个不匹配元素的比较。 + 此答案未显示现有答案中未涵盖的任何内容。
                    猜你喜欢
                    • 2015-12-23
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-04-21
                    • 2020-05-24
                    • 1970-01-01
                    • 2021-10-16
                    • 2014-07-15
                    相关资源
                    最近更新 更多