比较C#中数组的最简单方法


177

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

C#中有这样的事情吗?有什么“神奇”的方法可以比较C#中两个数组的内容?


1
在标签中添加了“ .net”,因为该技术可以在其他类似的基于.net的语言中使用。
Evan Plaice

3
对于阅读此书的每个人,请记住接受的答案是使用SequenceEqual。SequenceEqual不仅检查它们是否包含相同的数据,而且还检查它们是否以相同的顺序包含相同的数据
John Demetriou

Answers:


259

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


不过,这只有在它们处于相同顺序时才有效
John Demetriou

1
SequenceEqual可能不是一个明智的选择,因为它的当前实现可能会完全枚举其来源之一(如果它们仅在长度上有所不同)。使用数组,我们可以Length首先检查相等性,以避免为了最终yield枚举不同长度的数组false
弗雷德里克

71

Enumerable.SequenceEqualLINQ中使用。

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

1
请记住,这会引发空参数,因此请确保不要假定new int[] {1}.SequenceEquals(null) == false
sara

30

同样对于数组(和元组),您可以使用.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
}

请原谅,应该是1还是0 in a.StructuralCompare(b)
mafu 2015年

在大值类型数组上,使用它们会降低性能,因为它们的当前实现会将每个值框在一起进行比较。
弗雷德里克

18

对于.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)); 

编辑:发言太早。我可以将StructualEqualityCompare与IStructuralComparable进行比较吗?我想用两个对象数组调用CompareTo来找出哪个是“第一个”。我尝试了IStructuralComparable se1 = a1; Console.WriteLine(se1.CompareTo(a2,StructuralComparisons.StructuralEqualityComparer)); 正在获取:无法从“ System.Collections.IEqualityComparer”转换为“ System.Collections.IComparer”
shindigo

1
OK-正确的调用是:IStructuralComparable se1 = a1; Console.WriteLine(se1.CompareTo(a2,StructuralComparisons.StructuralComparer));
shindigo

14

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

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

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

值2是否包含值1中包含的所有值?

您可以使用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);

您会得到不同的结果。

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


2
包含相同值且以不同顺序排列的数组只是不相等。你觉得'Demetriou'=='uoirtemeD'吗?
edc65 '19

11

对于单元测试,可以使用CollectionAssert.AreEqual代替Assert.AreEqual

这可能是最简单的方法。


11

如果您希望适当地处理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;
        return array1.Count() == array2.Count() && !array1.Except(array2).Any();
    }
}

测试代码如下:

class Program
{
    static void Main(string[] args)
    {
        int[] a1 = new int[] { 1, 2, 3 };
        int[] a2 = new int[] { 3, 2, 1 };
        int[] a3 = new int[] { 1, 3 };
        int[] a4 = null;
        int[] a5 = null;
        int[] a6 = new int[0];

        Console.WriteLine(a1.ItemsEqual(a2)); // Output: True.
        Console.WriteLine(a2.ItemsEqual(a3)); // Output: False.
        Console.WriteLine(a4.ItemsEqual(a5)); // Output: True. No Exception.
        Console.WriteLine(a4.ItemsEqual(a3)); // Output: False. No Exception.
        Console.WriteLine(a5.ItemsEqual(a6)); // Output: False. No Exception.
    }
}

这对我很有帮助,但是如果a1 = { 1, 1 }a2 = { 1, 2 },则第一个测试返回错误的结果。返回声明应为return array1.Count() == array2.Count() && !array1.Except(array2).Any() && !array2.Except(array1).Any();
Polshgiant


2

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

1

逐元素比较?关于什么

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开发人员Linq示例的两个示例)


1
它不处理不同长度的数组(可能会错误地产生true)和null数组(将崩溃)。
弗雷德里克

1

我在视觉工作室做的,效果很好。用短代码比较每个索引的数组。

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


2
它不处理不同长度的数组(将崩溃),也不处理数组(也null将崩溃),并且它执行的操作超出了OP的要求。他只要求知道平等,而不计算有多少项不同或匹配。
弗雷德里克

0

假设数组相等意味着两个数组在相等的索引处具有相等的元素,则存在SequenceEqual答案IStructuralEquatable答案

但是两者都有缺点,从性能角度来看。

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] != second[i])
            return false;
    }
    return true;
}

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

因此,目前还没有,Arrays.equals().Net中没有真正等同于Java 的产品。


第一和第二个都为null会不会导致true?null == null,不是吗?
杰西·威廉姆斯

如果两者都为,则第一个测试将返回true null。你想说啥?
弗雷德里克

if(first [i]!= second [i])不适用于泛型。您必须使用if(!first [i] .Equals(second [i]))。
杰克格里芬
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.