40

I have two arrays. For example:

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

What is the best way to determine if they have the same elements?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
SudheerKovalam
  • 628
  • 2
  • 7
  • 13
  • Are you actually dealing with numbers or is that just for the example? – mmcdole Mar 16 '09 at 06:41
  • Can you use a List instead (already has Contains method)? – Ed S. Mar 16 '09 at 08:22
  • 1
    @ed it wasn't about a simple contains, but determining both array has the same elements, re-read the question and see the answers :) – eglasius Mar 17 '09 at 01:04
  • @Simucal I just used integers for the example here . IN my scenario, it could be an array of objects – SudheerKovalam Mar 17 '09 at 01:29
  • possible duplicate of [Comparing two collections for equality irrespective of the order of items in them](http://stackoverflow.com/questions/50098/comparing-two-collections-for-equality-irrespective-of-the-order-of-items-in-the) – nawfal Nov 08 '13 at 20:28

11 Answers11

104

You could also use SequenceEqual, provided the IEnumerable objects are sorted first.

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));
Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
Mike Nislick
  • 1,049
  • 2
  • 6
  • 2
21

Assuming that the values in the array are unique, you can implement a performant solution using LINQ:

// create a LINQ query that matches each item in ar1 with 
// its counterpart in ar2. we select "1" because we're only 
// interested in the count of pairs, not the values.
var q = from a in ar1 
        join b in ar2 on a equals b 
        select 1;

// if lengths of the arrays are equal and the count of matching pairs 
// is equal to the array length, then they must be equivalent.
bool equals = ar1.Length == ar2.Length && q.Count() == ar1.Length;

// when q.Count() is called, the join in the query gets translated
// to a hash-based lookup code which can run faster than nested
// for loops. 
Sedat Kapanoglu
  • 46,641
  • 25
  • 114
  • 148
  • Thanks for this code snippet. Works like a charm for my scenario!! – SudheerKovalam Mar 16 '09 at 07:49
  • 8
    I find this to be much slower than just doing a loop and comparing each item. The loop may not be as nice looking, but much, much faster. – David Basarab Jun 02 '09 at 14:45
  • I'm not sure about that. As far as I know LINQ-to-Objects generate intermediate hash tables to loop over joins which are much faster than a straight loop. – Sedat Kapanoglu Jun 01 '10 at 13:41
  • Here is my reference: http://stackoverflow.com/questions/1561622/is-linq-join-operator-using-nested-loop-merge-or-hashset-joins – Sedat Kapanoglu Jun 01 '10 at 13:47
  • 12
    This doesn't work when both of the arrays have duplicate values. If both arrays contain {2,2}, the join will have 4 elements instead of 2 and the expression will be false instead of true. – Evan M Jan 06 '12 at 21:03
  • 1
    @ssg I'm guessing you haven't actually researched any LINQ vs loop benchmark analyses. It's a generally accepted fact that LINQ is **always** going to be slower (certainly not *faster*) in most any scenario. It's strength is maintainability, not performance. [See here](http://stackoverflow.com/questions/14893924/for-vs-linq-performance-vs-future), [or here](http://geekswithblogs.net/BlackRabbitCoder/archive/2010/04/23/c-linq-vs-foreach---round-1.aspx), [or here](http://ox.no/posts/linq-vs-loop-a-performance-test). – arkon Mar 15 '15 at 00:35
  • @b1nary.atr0phy none of the links you provided is about `join`s. see http://stackoverflow.com/a/1561820/54937 for details about its behavior. – Sedat Kapanoglu Mar 15 '15 at 12:08
  • Linq has the _potential_ to be faster than a raw loop, but it depends on how you use Linq and the size of data being processed. For large loops involving lookups Linq joins can be significantly faster as they use a hashtable, however for small amounts of data the performance gain is less than the cost of setting up the hashtable in the first place. Generally Linq is quite readable, but when you start using joins it arguably becomes less so. As with all code, use whatever syntax you find to be the most readable until such a time as empirical testing demonstrates the need for optimization. – Neutrino May 14 '17 at 09:41
  • I know this is very old, but the LINQ code does not work for my scenario. I changed it to a for loop comparing each element, providing the length of the arrays are equal, and it is blazingly fast. – wiyosaya Jun 23 '23 at 14:29
  • @wiyosaya I'm glad that for loops work for your use case. It might be slow for large arrays due to the polynomial complexity of nested loops. – Sedat Kapanoglu Jun 26 '23 at 07:40
  • @Sedat Kapanoglu I'm not sure this applies, but In other code, I have a for loop that goes through an array searching for "white space" in a "visually readable" json file and removes it. I've had the size of that array be on the order of 2GB and it completes in far less time than you might think. With this code, if the arrays are the same length, there's really no complexity since the index of the equivalence relation for each array is the same. If an inequality is detected at any index, then the arrays are not equal. – wiyosaya Jun 27 '23 at 19:47
  • @wiyosaya Removing whitespace is an O(N) operation, so not comparable to nested for loops. You only need an array of ~50,000 elements in your nested for loops to reach the iteration count of your 2GB whitespace removal. – Sedat Kapanoglu Jun 28 '23 at 21:05
  • @Sedat Kapanoglu OK. you are right. But to determine equality of two arrays you can stop immediately if the arrays are different lengths. In my case. the arrays are in the same order so there is no need to for multiple nested loops. If the arrays are ordered differently, perhaps an array is not an ideal way to store the data. – wiyosaya Jun 30 '23 at 14:41
13

Will the values always be unique? If so, how about (after checking equal length):

var set = new HashSet<int>(array1);
bool allThere = array2.All(set.Contains);
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • marc , I could also compare via `IStructuralEquatable` (tuples and arrays). So when should I choose `IStructuralEquatable` vs `SequenceEqual` ? – Royi Namir Sep 29 '12 at 15:10
7
var shared = arr1.Intersect(arr2);
bool equals = arr1.Length == arr2.Length && shared.Count() == arr1.Length;
eglasius
  • 35,831
  • 5
  • 65
  • 110
7

Use extension methods (which are new in 3.0). If the length of the Intersection of the two arrays equals that of their Union then the arrays are equal.

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

Succinct.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Allen
  • 2,228
  • 18
  • 22
6

For the most efficient approach (Reflectored from Microsoft code), see Stack Overflow question Comparing two collections for equality irrespective of the order of items in them.

Community
  • 1
  • 1
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
5

Framework 4.0 introduced IStructuralEquatable interface which helps to compare types such as arrays or tuples:

 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
        }
    } 
komizo
  • 1,052
  • 14
  • 21
1

This will check that each array contains the same values in order.

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());
daebr
  • 11
  • 1
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

I have found the solution detailed here to be a very clean way, though a bit verbose for some people.

The best thing is that it works for other IEnumerables as well.

Cerebrus
  • 25,615
  • 8
  • 56
  • 70
0

There are, of course, many ways to compare arrays based on the structure. To add more to the answers above, you can write your own custom comparers. Let's say you want to check whether both, the 2 arrays, contain even elements - you define your comparison based on the business rules of your application, that's why it's so subjective.

Here is a way to do it, writing your own comparer. Please note that there is no much care about the GetHashCode() method and you have to write your custom equality logic, at this moment, based on the default behavior (compare reference types) .equals() will give you different results if you use another collection to hold the arrays and we are saying that these 2 arrays contain even numbers and they are therefore equal, but we are breaking the rule that "If two values x and y evaluate equal then they MUST have the same hashcode". Don't worry too much here because we are comparing integers. With that said here is the example:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp5
{
    class EvenComparer : EqualityComparer<int>
    {


        public override bool Equals(int x, int y)
        {
            if((x % 2 == 0 && y % 2 == 0))
            {
                return true;
            }

            return false;

        }

        public override int GetHashCode(int obj)
        {
            return obj.GetHashCode();
        }
    }


    class Program
    {
        static void Main(string[] args)
        {

            //If you want to check whether the arrays are equal in the sense of containing the same elements in the same order

            int[] Array1 =  { 2, 4, 6};
            int[] Array2 =  {8, 10, 12 };



            string[] arr1 = { "Jar Jar Binks", "Kill! Kill!", "Aaaaargh!" };
            string[] arr2 = { "Jar Jar Binks", "Kill! Kill!", "Aaaaargh!" };

            bool areEqual = (arr1 as IStructuralEquatable).Equals(arr2, StringComparer.Ordinal);
            bool areEqual2 = (Array1 as IStructuralEquatable).Equals(Array2, new EvenComparer());

            Console.WriteLine(areEqual);
            Console.WriteLine(areEqual2);


            Console.WriteLine(Array1.GetHashCode());
            Console.WriteLine(Array2.GetHashCode());

        }
    }
}

After reading the answers I realize that nobody specified that you have to include the

   using System.Collections;

namespace or you will get a missing using directive or assembly reference error for using the IStructuralEquatable interface.

Hope it helps someone someday

Community
  • 1
  • 1