Easiest way to compare arrays in C#
Asked Answered
P

19

252

In Java, Arrays.equals() allows to easily compare the content of two basic arrays (overloads are available for all the basic types).

Is there such a thing in C#? Is there any "magic" way of comparing the content of two arrays in C#?

Prolong answered 12/7, 2010 at 22:23 Comment(1)
To everyone reading this, keep in mind that the accepted answer is using SequenceEqual. SequenceEqual not only checks if they contain the same data, but also if they contain the same data in the same orderUnwonted
A
362

You could use Enumerable.SequenceEqual. This works for any IEnumerable<T>, not just arrays.

Anatto answered 12/7, 2010 at 22:25 Comment(4)
This only works if they are in the same order thoughUnwonted
SequenceEqual may not be a good choice performance wise, because its current implementation may fully enumerates one of its sources if they differ only by length. With arrays, we could check Length equality first, in order to avoid enumerating arrays of different lengths just to end-up yielding false.Standardbearer
@Frédéric, infact SequenceEqual will first compare the lengths, if both enumerables implement ICollection, see github.com/dotnet/runtime/blob/main/src/libraries/System.Linq/…Nelan
@quinmars, this answer was about .Net Framework, .Net Core was not existing in 2010. The relevant code is here. Still it is a good thing to know this point has changed in .Net Core. But it stays true for the .Net Framework.Standardbearer
G
113

Use Enumerable.SequenceEqual in LINQ.

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
Gateway answered 12/7, 2010 at 22:26 Comment(1)
Keep in mind that this throws for null arguments, so make sure to not assume that new int[] {1}.SequenceEquals(null) == falseCoplin
F
33

Also for arrays (and tuples) you can use new interfaces from .NET 4.0: IStructuralComparable and IStructuralEquatable. Using them you can not only check equality of arrays but also compare them.

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
}
Foxe answered 13/7, 2010 at 6:46 Comment(1)
On large value type arrays, there is a performance hit in using these, because their current implementation will box each value to compare.Standardbearer
U
23

SequenceEqual will only return true if two conditions or met.

  1. They contain the same elements.
  2. The elements are in the same order.

If you only want to check if they contain the same elements regardless of their order and your problem is of the type

Does values2 contain all the values contained in values1?

you can use LINQ extension method Enumerable.Except and then check if the result has any value. Here's an example

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
}

And also by using this you get the different items as well automatically. Two birds with one stone.

Keep in mind, if you execute your code like this

var result = values2.Except(values1);

you will get different results.

In my case I have a local copy of an array and want to check if anything has been removed from the original array so I use this method.

Unwonted answered 12/2, 2016 at 7:0 Comment(0)
W
21

For .NET 4.0 and higher you can compare elements in array or tuples via using StructuralComparisons type:

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)); 
Workout answered 7/11, 2014 at 9:33 Comment(0)
S
20

If you would like to handle null inputs gracefully, and ignore the order of items, try the following solution:

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();
    }
}

The test code looks like:

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.
}
Strephon answered 28/6, 2017 at 17:14 Comment(1)
Great answer. Wondering how I'd extend this to two dimensional arrays.Jahdai
C
12

For unit tests, you can use CollectionAssert.AreEqual instead of Assert.AreEqual.

It is probably the easiest way.

Conservancy answered 1/2, 2017 at 4:7 Comment(0)
P
8

For some applications may be better:

string.Join(",", arr1) == string.Join(",", arr2)
Pahlavi answered 19/7, 2017 at 22:29 Comment(0)
D
7

Assuming array equality means both arrays have equal elements at equal indexes, there is the SequenceEqual answer and the IStructuralEquatable answer.

But both have drawbacks, performance wise.

SequenceEqual implementation in .Net Framework will not shortcut when the arrays have different lengths, and so it may enumerate one of them entirely, comparing each of its elements.
This said, depending on the .Net flavor (like .Net5), it may shortcut, see this comment. So for an up-to-date .Net project, SequenceEqual should be a good choice.

IStructuralEquatable is not generic and may cause boxing of each compared value. Moreover it is not very straightforward to use and already calls for coding some helper methods hiding it away.

It may be better, performance wise, to use something like:

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;
}

But of course, that is not either some "magic way" of checking array equality.

So currently, no, there is not really an equivalent to Java Arrays.equals() in .Net.

Doughnut answered 14/2, 2019 at 12:45 Comment(0)
P
2

This LINQ solution works, not sure how it compares in performance to SequenceEquals. But it handles different array lengths and the .All will exit on the first item that is not equal without iterating through the whole array.

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)
            );
Parallelize answered 27/6, 2019 at 16:4 Comment(0)
F
1

elementwise compare ? what about

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)");
}

Replace the (a==b) condition by anything you'd like to compare in a and b.

(this combines two examples from MSDN developer Linq samples)

Fitter answered 15/4, 2016 at 12:54 Comment(1)
It does not handle arrays of different lengths (may incorrectly yield true) and null arrays (will crash).Standardbearer
K
1

I did this in visual studios and it worked perfectly; comparing arrays index by index with short this code.

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);
        }

the output will be; The matching numbers are 7 The non matching numbers are 3

Kristoferkristoffer answered 24/12, 2016 at 5:39 Comment(1)
It does not handle arrays of different lengths (will crash), null arrays (will crash too), and it does something else than what the OP asked. He only asked to know equality, without counting how many items differ or match.Standardbearer
O
1

I was looking to determine if two sets had equivalent contents, in any order. That meant that, for each element in set A there were equal numbers of elements with that value in both sets. I wanted to account for duplicates (so {1,2,2,3} and {1,2,3,3} should not be considered "the same").

This is what I came up with (note that IsNullOrEmpty is another static extension method that returns true if the enumerable is null or has 0 elements):

    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;
    }
Opium answered 13/11, 2020 at 21:32 Comment(0)
S
1

You can also use array1.ToList().All(x => array2.Contains(x)) if you need to compare arrays which have not the same order

Subarid answered 19/1, 2022 at 23:16 Comment(4)
Hello, and welcome to StackOverflow! This answer will not compare the arrays thoroughly, as it will return true if array1 contains [1], and array2 contains [1,2,3,4,5]. Other answers on this question related to using intersections answer it more thoroughly.Filip
It would be correct if add array1.Length == array2.LengthAboveground
@SergeiShvets, no that's also not true, because [1,1,1,1,2] and [1,2,2,2,2] would be equal according to your logic.Kuehn
@Kuehn agree, anything can't help this answer to work correctlyAboveground
C
1

List Patterns is added in C#11 .Net 7 RC2.

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]);  // True
Console.WriteLine(numbers is [1, 2, 4]);  // False
Commence answered 4/11, 2022 at 17:43 Comment(0)
O
0

You can use 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");
Othilia answered 28/9, 2020 at 11:55 Comment(1)
I do not think that this is what OP asks for. How does this compare the arrays? It only identifies, if the arrays have any common element. That's hardly an equivalent of Java Arrays.equals().Hagai
J
0

If you don't want to compare the order but you do want to compare the count of each item, including handling null values, then I've written an extension method for this.

It gives for example the following results:

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

Here is the code:

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;
        }
    }
}

It only enumerates each enumerable once, but it does create a dictionary for each enumerable and iterates those once too. I'd be interested in ways to improve this.

Jockey answered 2/12, 2020 at 19:19 Comment(0)
O
0

Check the answer to this thread which converts one of the array to a HashSet and uses SetEquals for comparison with the other array. Note however that this does not check for order or duplicates.

Overmatter answered 24/3, 2021 at 12:36 Comment(0)
V
-2
        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
Vig answered 21/10, 2020 at 11:36 Comment(1)
That's quite suboptimal. You should stop the comparison on the first non-matching element. + This answer does not show anything that is not covered in the existing answers already.Hagai

© 2022 - 2024 — McMap. All rights reserved.