21

I have two byte arrays in C# using .NET 3.0.

What is the "most efficient" way to compare whether the two byte arrays contains the same content for each element?

For example, byte array {0x1, 0x2} is the same as {0x1, 0x2}. But byte array {0x1, 0x2} and byte array {0x2, 0x1} are not the same.

1

6 Answers 6

47

Well, you could use:

public static bool ByteArraysEqual(byte[] b1, byte[] b2)
{
    if (b1 == b2) return true;
    if (b1 == null || b2 == null) return false;
    if (b1.Length != b2.Length) return false;
    for (int i=0; i < b1.Length; i++)
    {
        if (b1[i] != b2[i]) return false;
    }
    return true;
}

(I normally use braces for everything, but I thought I'd experiment with this layout style just for a change...)

This has a few optimisations which SequenceEqual can't (or doesn't) perform - such as the up-front length check. Direct array access will also be a bit more efficient than using the enumerator.

Admittedly it's unlikely to make a significant difference in most cases...

You could possibly make it faster in unmanaged code by making it compare 32 or 64 bits at a time instead of 8 - but I wouldn't like to code that on the fly.

Sign up to request clarification or add additional context in comments.

3 Comments

For large arrays, say 10k, would parallelizing be an efficient optimization or would the threading overhead be to too much?
What's your take on IStructuralEquatable for this purpose?
@Lijo: I confess I've never fully understood IStructuralEquatable and when it's appropriate.
29

You can use the SequenceEqual method:

bool areEqual = firstArray.SequenceEqual(secondArray);

As mentioned in the comments, SequenceEqual requires .NET 3.5 (or LINQBridge if you're using VS2008 and targeting an earlier version of the framework).

7 Comments

The most efficient way I think.
Not in terms of execution time it's not.
@Veton: It's certainly the least typing! See Jon's answer for a few additional optimisations.
(Try comparing a byte array containing 1,000,000 entries with one containing 1,000,001 entries via SequenceEqual. It will go right to the end before noticing they have different lengths...)
This also doesn't work (without something like LINQBridge) in .NET 3.0 as required in the question... although it's possible that the OP meant .NET 3.5.
|
5

Jon mentioned comparing multiple bytes at once using unsafe code, so I had to give it a go:

public unsafe bool ByteArraysEqual(byte[] b1, byte[] b2) {
   if (b1 == b2) return true;
   if (b1 == null || b2 == null) return false;
   if (b1.Length != b2.Length) return false;
   int len = b1.Length;
   fixed (byte* p1 = b1, p2 = b2) {
      int* i1 = (int*)p1;
      int* i2 = (int*)p2;
      while (len >= 4) {
         if (*i1 != *i2) return false;
         i1++;
         i2++;
         len -= 4;
      }
      byte* c1 = (byte*)i1;
      byte* c2 = (byte*)i2;
      while (len > 0) {
         if (*c1 != *c2) return false;
         c1++;
         c2++;
         len--;
      }
   }
   return true;
}

The safe code gets pretty optimised (the compiler knows that it doesn't have to check index boundaries for example), so I wouldn't expect the unsafe code to be very much faster. Any significant difference would come from the ability to compare several bytes at once.

3 Comments

Good concept, although the code doesn't compile: "Cannot assign to 'p1' because it is a 'fixed variable'"
@Edward Brey: You are correct, that won't work. You need to declare new pointers inside the block to have them changeable. I have corrected the code.
It's faster to use longs (8 bytes) in the comp, even on 32bit machines.
4

If you are not too concerned about performance, you can consider IStructuralEquatable.

.NET Framework Supported in: 4.5, 4

Structural equality means that two objects are equal because they have equal values. It differs from reference equality.

Example:

static bool ByteArrayCompare(byte[] a1, byte[] a2) 
{
  IStructuralEquatable eqa1 = a1;
  return eqa1.Equals(a2, StructuralComparisons.StructuralEqualityComparer);
}

REFERENCE

  1. What problem does IStructuralEquatable and IStructuralComparable solve?
  2. Why aren't IStructuralEquatable and IStructuralComparable generic?
  3. IStructuralEquatable Interface

1 Comment

Giving this post a point: this might be a way to do things when we are using the recent versions of the framework.
2

If you want it to be really fast, you can use unsafe code (which isn't always possible):

    public static bool ArraysEqual(byte[] b1, byte[] b2)
    {
        unsafe
        {
            if (b1.Length != b2.Length)
                return false;

            int n = b1.Length;

            fixed (byte *p1 = b1, p2 = b2)
            {
                byte *ptr1 = p1;
                byte *ptr2 = p2;

                while (n-- > 0)
                {
                    if (*ptr1++ != *ptr2++)
                        return false;
                }
            }

            return true;
        }
    }

Comments

2

Update for .NET 6.

These days Enumerable.SequenceEqual method is still the best option:

var byteArray1 = new[]{0x01, 0x02};
var byteArray2 = new[]{0x01, 0x02};

bool isEqual = byteArray1.SequenceEqual(byteArray2);

Though, another option is also available out-of-the-box – ReadOnlySpan<T>.SequenceEqual, e.g.:

bool isEqual = new Span<byte>(byteArray1).SequenceEqual(new Span<byte>(byteArray2));

The Span approach used to be faster in the pre-.NET 6 time, but the MS folks drastically optimised implementation of Enumerable.SequenceEqual that's now using ReadOnlySpan<T> under the hood (PR 1, PR 2). See Performance improvements in .NET 6 for more info.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.