38

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,030
  • 21
  • 100
  • 124
SudheerKovalam
  • 608
  • 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

102

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,046
  • 14
  • 81
  • 111
Mike Nislick
  • 1,029
  • 2
  • 6
  • 2
21

By using LINQ you can implement it expressively and performant:

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;
Sedat Kapanoglu
  • 44,742
  • 25
  • 114
  • 143
  • Thanks for this code snippet. Works like a charm for my scenario!! – SudheerKovalam Mar 16 '09 at 07:49
  • 7
    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
12

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
  • 976,458
  • 251
  • 2,474
  • 2,830
  • 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,469
  • 4
  • 62
  • 107
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
  • 95,331
  • 80
  • 293
  • 426
Allen
  • 2,208
  • 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
  • 35,000
  • 11
  • 158
  • 195
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,050
  • 14
  • 20
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

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,440
  • 8
  • 55
  • 70
0
    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;
    }
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