Comparing Two Byte Arrays in .Net

Comparing two byte arrays in .NET

Edit: modern fast way is to use a1.SequenceEquals(a2)

User gil suggested unsafe code which spawned this solution:

// Copyright (c) 2008-2013 Hafthor Stefansson
// Distributed under the MIT/X11 software license
// Ref: http://www.opensource.org/licenses/mit-license.php.
static unsafe bool UnsafeCompare(byte[] a1, byte[] a2) {
unchecked {
if(a1==a2) return true;
if(a1==null || a2==null || a1.Length!=a2.Length)
return false;
fixed (byte* p1=a1, p2=a2) {
byte* x1=p1, x2=p2;
int l = a1.Length;
for (int i=0; i < l/8; i++, x1+=8, x2+=8)
if (*((long*)x1) != *((long*)x2)) return false;
if ((l & 4)!=0) { if (*((int*)x1)!=*((int*)x2)) return false; x1+=4; x2+=4; }
if ((l & 2)!=0) { if (*((short*)x1)!=*((short*)x2)) return false; x1+=2; x2+=2; }
if ((l & 1)!=0) if (*((byte*)x1) != *((byte*)x2)) return false;
return true;
}
}
}

which does 64-bit based comparison for as much of the array as possible. This kind of counts on the fact that the arrays start qword aligned. It'll work if not qword aligned, just not as fast as if it were.

It performs about seven timers faster than the simple `for` loop. Using the J# library performed equivalently to the original `for` loop. Using .SequenceEqual runs around seven times slower; I think just because it is using IEnumerator.MoveNext. I imagine LINQ-based solutions being at least that slow or worse.

Checking equality for two byte arrays

You need to add a return value somewhere. This should work:

public bool Equality(byte[] a1, byte[] b1)
{
int i;
if (a1.Length == b1.Length)
{
i = 0;
while (i < a1.Length && (a1[i]==b1[i])) //Earlier it was a1[i]!=b1[i]
{
i++;
}
if (i == a1.Length)
{
return true;
}
}

return false;
}

But this is much simpler:

return a1.SequenceEqual(b1);

Alternatively, you could use IStructuralEquatable from .NET 4:

return ((IStructuralEquatable)a1).Equals(b1, StructuralComparisons.StructuralEqualityComparer)

If performance is a concern, I'd recommend rewriting your code to use the Binary class, which is specifically optimized for this kind of use case:

public bool Equality(Binary a1, Binary b1)
{
return a1.Equals(b1);
}

A quick benchmark on my machine gives the following stats:

Method                   Min         Max         Avg
binary equal: 0.868 3.076 0.933 (best)
for loop: 2.636 10.004 3.065
sequence equal: 8.940 30.124 10.258
structure equal: 155.644 381.052 170.693

Download this LINQPad file to run the benchmark yourself.

How to compare two arrays of bytes

Try using the SequenceEqual extension method. For example:

byte[] a1 = new byte[] { 1, 2, 3 };
byte[] a2 = new byte[] { 1, 2, 3 };
bool areEqual = a1.SequenceEqual(a2); // true

C# - byte array - byte[] - Is there a simple comparer?

You are looking for SequenceEqual method.

a.SequenceEqual(b);

Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type.


Comparing 2 hashed byte arrays

Basically, if you only have the byte hash in DB, you want to compare two byte array ?

You can get this here: Comparing two byte arrays in .NET

One of the options that might work for you is:

StructuralComparisons.StructuralEqualityComparer.Equals(hashedBytes,
previousHashedBytes)

How do i compare byte arrays in vb.net

Use SequenceEqual

    Dim foo() As Byte = {1, 2, 3, 4}
Dim barT() As Byte = {1, 2, 3, 4}
Dim barF() As Byte = {1, 2, 3, 5}

Dim fooEqbarT As Boolean = foo.SequenceEqual(barT)
Dim fooEqbarF As Boolean = foo.SequenceEqual(barF)

Debug.WriteLine(fooEqbarT)
Debug.WriteLine(fooEqbarF)

Compare two small files

    Dim path1 As String = "pathnameoffirstfile"
Dim path2 As String = "pathnameofsecondfile"

Dim foo() As Byte = IO.File.ReadAllBytes(path1)
Dim bar() As Byte = IO.File.ReadAllBytes(path2)

If foo.SequenceEqual(bar) Then
'identical
Else
'different
End If

C# Compare two byte[] arrays containing text as lowercase

Lowercase and uppercase ACSII and UTF8 code's byte representation have an offset of 32 (or hex20), so you can implement a comparison of x == byte[x] || x == byte[x+32] with x=uppercase char value.

edit:

suppose you really have to deal only with small and capital english letters, you can hack around with bitwise operations to speed things up, as you can handle 8 byte / chars at once, because those only differ by the 3rd most significant bit:

'b' & 0b_1101_1111 == 'B' & 0b_1101_1111

so you could handle the byte array in 8 byte chunks:

void Main()
{
byte[] a = "ASDADAGF".Select(x => (byte)(x) ).ToArray();
byte[] b = "asdAdAGF".Select(x => (byte)(x) ).ToArray();
bitCompared(a,b).Dump();
}

static bool bitCompared( byte[] b1, byte[]b2)
{
UInt64 a = BitConverter.ToUInt64(b1, 0); //loop over the index
UInt64 b = BitConverter.ToUInt64(b2, 0);
UInt64 mask =0b_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111;
return (a &= mask) == (b &= mask);
}

afaik there are also even more ways to optimize with SIMD and other low level "hacks".....

Comparing two Byte Arrays byte by byte and return there difference?

If you just want a count of the number of differences try this

            byte[] array1 = new byte[2];
byte[] array2 = new byte[2];

int diff = array1.Where((x, i) => x != array2[i]).Count();

How to compare two byte arrays with greater than or less than operator value in C# or Linq?

One way is to use IStructuralComparable, which Array implicitly implements:

byte[] rv1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01 };
byte[] rv2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05 };

var result = ((IStructuralComparable)rv1).CompareTo(rv2, Comparer<byte>.Default); // returns negative value, because rv1 < rv2

If for some reason you want to use BitConverter, you have to reverse arrays, because BitConverter is little endian on most architectures (to be safe - you should check BitConverter.IsLittleEndian field and reverse only if it returns true). Note that it's not very efficient to do this.

var i1 = BitConverter.ToUInt64(rv1.Reverse().ToArray(), 0);
var i2 = BitConverter.ToUInt64(rv2.Reverse().ToArray(), 0);

Now if you use Entity Framework and need to compare timestamps in database query, situation is a bit different, because Entity Framework will inspect your query expression looking for patterns it understands. It does not understand IStructuralComparable comparisions (and BitConverter conversions too of course), so you have to use a trick. Declare extension method for byte array with the name Compare:

static class ArrayExtensions {
public static int Compare(this byte[] b1, byte[] b2) {
// you can as well just throw NotImplementedException here, EF will not call this method directly
if (b1 == null && b2 == null)
return 0;
else if (b1 == null)
return -1;
else if (b2 == null)
return 1;
return ((IStructuralComparable) b1).CompareTo(b2, Comparer<byte>.Default);
}
}

And use that in EF LINQ query:

var result = ctx.TestTables.Where(c => c.RowVersion.Compare(rv1) > 0).ToList();

When analyzing, EF will see method with name Compare and compatible signature and will translate that into correct sql query (select * from Table where RowVersion > @yourVersion)

c# compare byte arrays

As other comments have already stated, the problem is that you are comparing pointers, not values. The correct code should be:

if (*(intfirst + i) != *(intsecond + i))

But I'd like to point out a deeper issues in your code.

  • If the input byte arrays have lengths that don't align with 4
    (first.Length % 4 != 0) you will get false positives because you'll
    be essentially swallowing all misaligned items:

    {1, 2, 3, 4, 5}
    {1, 2, 3, 4, 7}

    Will return true when they are obviously not the same.

  • You should be checking, before anything else, that both
    arrays have the same length and bailing out fast if they don't. You'll
    run into all kind of issues otherwise.

    {1, 2, 3, 0}
    {1, 2, 3}

    Will also return true when it shoudn't.



Related Topics



Leave a reply



Submit