在C#中测试数组相等性

40

我有两个数组,例如:

int[] Array1 = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] Array2 = new[] {9, 1, 4, 5, 2, 3, 6, 7, 8};

如何确定两个集合是否包含相同的元素?


你是否真正处理数字,还是仅仅为了例子? - mmcdole
你可以使用 List<T> 替代吗?(它已经有 Contains 方法了) - Ed S.
1
@ed,这不仅仅是简单的包含关系,而是要确定两个数组是否具有相同的元素,请重新阅读问题并查看答案 :) - eglasius
@Simucal 这里我只是举例使用了整数。在我的情况下,它可能是一个对象数组。 - SudheerKovalam
11个回答

104

如果IEnumerable对象事先排序,你也可以使用SequenceEqual

int[] a1 = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };    
int[] a2 = new[] { 9, 1, 4, 5, 2, 3, 6, 7, 8 };    

bool equals = a1.OrderBy(a => a).SequenceEqual(a2.OrderBy(a => a));

2
是的,排序/顺序,然后使用SequenceEqual。 - Jake Berger

21

通过使用LINQ,您可以以表达性强和高效的方式实现它:

var q = from a in ar1
        join b in ar2 on a equals b
        select a;

bool equals = ar1.Length == ar2.Length && q.Count() == ar1.Length;

8
我发现这种方法比直接用循环一个个比较要慢得多。虽然循环看起来可能不太好看,但速度快得多,非常非常快。 - David Basarab
12
当两个数组都有重复值时,这种方法将无法正常工作。如果两个数组都包含{2,2},则连接后会有4个元素而不是2个,表达式的结果将变为false而不是true。 - Evan M
1
@ssg 我猜你并没有真正研究过任何关于LINQ与循环的基准分析。普遍认为,在大多数情况下,LINQ总是会比循环慢(当然不可能更快)。它的优势在于可维护性,而不是性能。请参见这里或者这里或者这里 - arkon
@b1nary.atr0phy,你提供的链接都不是关于join的。请参考https://dev59.com/CknSa4cB1Zd3GeqPQ8hz#1561820了解其行为细节。 - Sedat Kapanoglu
Linq有可能比原始循环更快,但这取决于您如何使用Linq以及正在处理的数据大小。对于涉及查找的大型循环,Linq连接可以显着提高速度,因为它们使用哈希表,但是对于少量数据而言,性能提升不及首次设置哈希表的成本。通常情况下,Linq非常易读,但是当您开始使用连接时,它可能变得不那么易读。与所有代码一样,在经验测试证明需要优化之前,请使用您认为最易读的语法。 - Neutrino
显示剩余9条评论

13

这些值会一直是唯一的吗?如果是,那么在检查相等长度后如何处理:

var set = new HashSet<int>(array1);
bool allThere = array2.All(set.Contains);

Marc,我也可以通过使用“IStructuralEquatable”(元组和数组)进行比较。那么何时应选择“IStructuralEquatable”而不是“SequenceEqual”? - Royi Namir

7

使用扩展方法(在3.0中是新功能)。如果两个数组的交集长度等于它们的并集长度,则这两个数组相等。

bool equals = arrayA.Intersect(arrayB).Count() == arrayA.Union(arrayB).Count()

简洁明了。


7
var shared = arr1.Intersect(arr2);
bool equals = arr1.Length == arr2.Length && shared.Count() == arr1.Length;

6

5

Framework 4.0引入了IStructuralEquatable接口,它有助于比较数组或元组等类型:

 class Program
    {
        static void Main()
        {
            int[] array1 = { 1, 2, 3 };
            int[] array2 = { 1, 2, 3 };
            IStructuralEquatable structuralEquator = array1;
            Console.WriteLine(array1.Equals(array2));                                  // False
            Console.WriteLine(structuralEquator.Equals(array2, EqualityComparer<int>.Default));  // True

            // string arrays
            string[] a1 = "a b c d e f g".Split();
            string[] a2 = "A B C D E F G".Split();
            IStructuralEquatable structuralEquator1 = a1;
            bool areEqual = structuralEquator1.Equals(a2, StringComparer.InvariantCultureIgnoreCase);

            Console.WriteLine("Arrays of strings are equal:"+  areEqual);

            //tuples
            var firstTuple = Tuple.Create(1, "aaaaa");
            var secondTuple = Tuple.Create(1, "AAAAA");
            IStructuralEquatable structuralEquator2 = firstTuple;
            bool areTuplesEqual = structuralEquator2.Equals(secondTuple, StringComparer.InvariantCultureIgnoreCase);

            Console.WriteLine("Are tuples equal:" + areTuplesEqual);
            IStructuralComparable sc1 = firstTuple;
            int comparisonResult = sc1.CompareTo(secondTuple, StringComparer.InvariantCultureIgnoreCase);
            Console.WriteLine("Tuples comarison result:" + comparisonResult);//0
        }
    } 

1
    public static bool ValueEquals(Array array1, Array array2)
    {
        if( array1 == null && array2 == null )
        {
            return true;
        }

        if( (array1 == null) || (array2 == null) )
        {
            return false;
        }

        if( array1.Length != array2.Length )
        {
            return false;
        }
        if( array1.Equals(array2))
        {
           return true;
        }
        else
        {
            for (int Index = 0; Index < array1.Length; Index++)
            {
                if( !Equals(array1.GetValue(Index), array2.GetValue(Index)) )
                {
                    return false;
                }
            }
        }
        return true;
    }

1

这将检查每个数组是否按顺序包含相同的值。

int[] ar1 = { 1, 1, 5, 2, 4, 6, 4 };
int[] ar2 = { 1, 1, 5, 2, 4, 6, 4 };

var query = ar1.Where((b, i) => b == ar2[i]);

Assert.AreEqual(ar1.Length, query.Count());

那看起来像是 NUnit 的一个方法,而不是通用解决方案。 - Oskar Berggren

1

我发现这里提供的解决方案非常干净,虽然对于某些人来说有点啰嗦。

最好的事情是它也适用于其他IEnumerables。


该链接描述了SequenceEqual(在.NET 3.5中),并且对于这些数据将返回false,因为它们的顺序不同。 - Marc Gravell
1
参考代码,使用扩展方法可以这样写:bool areEqual = array1.SequenceEqual(array2); - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接