Reputation: 45801
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.
Upvotes: 21
Views: 31099
Reputation: 8954
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.
Upvotes: 2
Reputation: 1503130
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.
Upvotes: 47
Reputation: 22661
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
Upvotes: 4
Reputation: 700720
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.
Upvotes: 5
Reputation: 269588
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).
Upvotes: 29
Reputation: 171864
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;
}
}
Upvotes: 2