6

I just have to do a simple comparison i.e.

byte[] keya = System.Text.Encoding.ASCII.GetBytes("myFamilyColumn:1");
byte[] keyb = System.Text.Encoding.ASCII.GetBytes("myFamilyColumn:1");
Console.WriteLine(keya == keyb);

but the result is false, and their hash code is also different, am i missing something here?

Thanks in advance !

David
  • 208,112
  • 36
  • 198
  • 279
Ali
  • 1,648
  • 2
  • 26
  • 48
  • 2
    If you can use LINQ, you can do `keya.SequenceEqual(keyb)`. – Ani Jan 04 '11 at 21:06
  • Unfortunately that's Not available in mono. – Ali Jan 04 '11 at 21:34
  • 3
    Isn't this a duplicate of [Compare Two .Net Array Objects (byte arrays)](http://stackoverflow.com/q/486749/15639)? – MarkJ Jan 05 '11 at 09:50
  • Possible duplicate of [Compare two .NET Array objects](https://stackoverflow.com/questions/486749/compare-two-net-array-objects) – yaakov Mar 27 '19 at 23:49
  • I wish I could -1 Microsoft for this default behavior in .NET. Or am I missing something too? Why on Earth should two byte arrays containing exactly the same bytes return false? This happens using keya.Equals(keyb), too. – gog Jun 10 '20 at 12:07

4 Answers4

12

I don't believe there's anything in the framework which will give array equality in the way you'd want. However, it's not too hard to write your own implementation of IEqualityComparer<T> for arrays. For example (compiled but untested):

public static class ArrayEqualityComparer
{
    public static IEqualityComparer<T[]> Create<T>(
        IEqualityComparer<T> comparer)
    {
        return new ArrayEqualityComparer<T>(comparer);
    }
}

public sealed class ArrayEqualityComparer<T> : IEqualityComparer<T[]>
{
    private static readonly IEqualityComparer<T[]> defaultInstance = new
        ArrayEqualityComparer<T>();

    public static IEqualityComparer<T[]> Default
    {
        get { return defaultInstance; }
    }

    private readonly IEqualityComparer<T> elementComparer;

    public ArrayEqualityComparer() : this(EqualityComparer<T>.Default)
    {
    }

    public ArrayEqualityComparer(IEqualityComparer<T> elementComparer)
    {
        this.elementComparer = elementComparer;        
    }

    public bool Equals(T[] x, T[] y)
    {
        if (x == y)
        {
            return true;
        }
        if (x == null || y == null)
        {
            return false;
        }
        if (x.Length != y.Length)
        {
            return false;
        }
        for (int i = 0; i < x.Length; i++)
        {
            if (!elementComparer.Equals(x[i], y[i]))
            {
                return false;
            }
        }
        return true;
    }

    public int GetHashCode(T[] array)
    {
        if (array == null)
        {
            return 0;
        }
        int hash = 23;
        foreach (T item in array)
        {
            hash = hash * 31 + elementComparer.GetHashCode(item);
        }
        return hash;
    }
}

(Note that this currently assumes that elementComparer will cope with null values for both GetHashCode and Equals. The interface doesn't guarantee that, but the default equality comparers actually do handle it. You could modify the above code to be more robust, of course... I just don't have time right now.)

Usage:

IEqualityComparer<byte[]> x = ArrayEqualityComparer<byte>.Default;
bool equal = x.Equals(bytes1, bytes2);

IEqualityComparer<string[]> y = 
    ArrayEqualityComparer.Create(StringComparer.OrdinalIgnoreCase);
bool whatever = x.Equals(new[][] { "X", "Y" }, new[] { "x", "y" });
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon I'm really surprised you're not commenting on the use of System.Text.Encoding.ASCII.GetBytes – Conrad Frix Jan 04 '11 at 21:13
  • 1
    @Conrad: I'm assuming that that was just the simplest way the OP could think of to create two "equal" byte arrays. – Jon Skeet Jan 04 '11 at 21:14
  • I prefer [your answer from Jan 2009](http://stackoverflow.com/questions/486749/compare-two-net-array-objects/486781#486781) to this [duplicate question](http://stackoverflow.com/questions/486749/compare-two-net-array-objects). The code's so much briefer in the other answer. – MarkJ Jan 05 '11 at 09:52
  • 1
    @MarkJ: They both have their places. For example, if you want to create a `HashSet` of arrays, you really want an `IEqualityComparer`. If you *just* want to compare for equality in code that you own, the 2009 answer is possibly more appropriate. – Jon Skeet Jan 05 '11 at 09:59
  • Any thoughts on whether it's a good idea to have such an expensive GetHashCode? Would it be better to pick, say, the first 5 items to combine? Or inject the hashcode strategy into the constructor of the equality-comparer? – Ani Jan 05 '11 at 13:45
  • @Ani: Generally a hash code will only be computed once - whereas Equals will be called on every potential match. In particular, the cheaper you make the hash code, the more times Equals will be called. – Jon Skeet Jan 05 '11 at 13:46
  • If we had a thousand arrays of a million elements each that were *wildly* different from each other, that one hash-code computation will be far more significant than hundreds of equality comparisons, most of which should quick-reject really quickly. Thoughts? The reason I'm harping on this is that I've never had to write a GetHashCode for a collection before, and I was wondering if this is a good approach. – Ani Jan 05 '11 at 13:54
  • @Ani: Yes, that's a possibility. You certainly *could* parameterize the constructor to only hash a certain number of elements. I'd probably wait until it was needed before adding that functionality though. – Jon Skeet Jan 05 '11 at 13:57
4

keya and keyb are two entirely separate objects that just happen to contain the same bytes.

If you want to compare to see if two strings have the same characters, perhaps you should look at methods like String.Equals?

Anon.
  • 58,739
  • 8
  • 81
  • 86
  • 2
    Yes, or iterate through the arrays and compare each pair of bytes. – Klaus Byskov Pedersen Jan 04 '11 at 21:04
  • Actually i don't want to iterate the collection of keys which are of byte[] datatype because i already know the key and when i get the bytes from string then it didn't return me object correspond to that key but when i use the reference of the key from the iteration i found the object, why is that so? – Ali Jan 04 '11 at 21:20
  • @Ali: It sounds like you're using these byte arrays as keys into a collection? Firstly, if these are representations of strings then it would be better to use the strings themselves as keys, otherwise, you can write your own equality comparer and tell the collection to use that instead of the default. – Anon. Jan 04 '11 at 21:27
  • I guess I've to write my own equality comparer. – Ali Jan 04 '11 at 21:44
1

This generic extension should do the trick:

public static class ArrayExtensions
{
    public static bool ElementsEqual<T>(this T[] left, T[] right)
        where T : IEquatable<T>
    {
        if (left == null || right == null)
        {
            return !(left == null ^ right == null);
        }
        else if (left.Length != right.Length)
        {
            return false;
        }

        for (int i = 0; i < left.Length; i++)
        {
            if (!left[i].Equals(right[i]))
            {
                return false;
            }
        }

        return true;
    }
}
ChaosPandion
  • 77,506
  • 18
  • 119
  • 157
1

Arrays are reference types so testing for equality checks to see if the pointers are the same. They're not.

If you want to compare the elements and not the arrays themselves, you can import System.Linq and use keya.SequenceEqual(keyb).

Trystan Spangler
  • 1,685
  • 11
  • 20