C# Hashcode for Array of Ints

C# hashcode for array of ints

Not very clever, but sufficient for most practical purposes:

EDIT: changed due to comment of Henk Holterman, thanks for that.

  int hc = array.Length;
foreach (int val in array)
{
hc = unchecked(hc * 314159 + val);
}

If you need something more sophisticated, look here.

Hashing an array in c#

To compute a hash code using the elements of an array, you can cast the array to IStructuralEquatable and then call the GetHashCode(IEqualityComparer) method, passing a comparer for the type of elements in the array.

(The cast is necessary because the Array class implements the method explicitly.)

For example, if your object has an int array, then you can implement GetHashCode like this:

public override int GetHashCode()
{
return ((IStructuralEquatable)this.array).GetHashCode(EqualityComparer<int>.Default);
}

In case you're curious, here's how the Array class implements the GetHashCode method (from the Reference Source):

internal static int CombineHashCodes(int h1, int h2) {
return (((h1 << 5) + h1) ^ h2);
}

int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
if (comparer == null)
throw new ArgumentNullException("comparer");
Contract.EndContractBlock();

int ret = 0;

for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) {
ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
}

return ret;
}

As you can see, the current implementation only uses the last eight elements of the array.

Hash integer array

Have you considered using a space-filling curve to generate the hash? This will minimize (or eliminate) collisions for the chosen resolution (maxX, maxY)

Here are two SO questions and their answers that use this method.

  1. Mapping N-dimensional value to a point on Hilbert curve
  2. Calculate the Hilbert value of a point for use in a Hilbert R-Tree?

Hope this helps!

GetHashCode() on byte[] array

Like other non-primitive built-in types, it just returns something arbitrary. It definitely doesn't try to hash the contents of the array. See this answer.

Different Hash code for same arrays in C#

There is no way to override the GetHashCode method from the array class. But you can wrap you array inside another class and them use some of its items to specify its hash key.

public class WrappedArray
{
sbyte[] _inner = new sbyte[10]

//...

override public int GetHashCode()
{
return _inner[0] ^ _inner[1] ^ _inner[2];
}
}

It is just an idea. The hash codes don't need to be unique for each object, because hash structures are designed to deal with collisions.

How to hash an int[] in c#

You can use something like this:

public static int CombineHashCodes(params int[] hashCodes)
{
if (hashCodes == null)
{
throw new ArgumentNullException("hashCodes");
}

if (hashCodes.Length == 0)
{
throw new IndexOutOfRangeException();
}

if (hashCodes.Length == 1)
{
return hashCodes[0];
}

var result = hashCodes[0];

for (var i = 1; i < hashCodes.Length; i++)
{
result = CombineHashCodes(result, hashCodes[i]);
}

return result;
}

private static int CombineHashCodes(int h1, int h2)
{
return (h1 << 5) + h1 ^ h2;

// another implementation
//unchecked
//{
// var hash = 17;

// hash = hash * 23 + h1;
// hash = hash * 23 + h2;

// return hash;
//}
}

Suitable hash code methods for an array of bytes?

Any of the built-in hashing functions should do; depending on how much you care about collisions these are your options (from most collisions to least):

  • MD5
  • SHA1
  • SHA256
  • SHA384
  • SHA512

They are as simple to use as:

var hash = SHA1.Create().ComputeHash(data);

Bonus Marks: If you don't care about security (which I don't think you do given that you are getting the hashes for images) you might want to look into Murmur hash, which is designed for content hashing and not secure hashing (and is thus much faster). It isn't, however, in the framework so you will have to find an implementation (and you should probably go for Murmur3).

Edit: If you are looking for a HASHCODE for a byte[] array it's entirely up to you, it usually consists of bit shifting (by primes) and XORing. E.g.

public class ByteArrayEqualityComparer : IEqualityComparer<byte[]>
{
public static readonly ByteArrayEqualityComparer Default = new ByteArrayEqualityComparer();
private ByteArrayEqualityComparer() { }

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

public int GetHashCode(byte[] obj)
{
if (obj == null || obj.Length == 0)
return 0;
var hashCode = 0;
for (var i = 0; i < obj.Length; i++)
// Rotate by 3 bits and XOR the new value.
hashCode = (hashCode << 3) | (hashCode >> (29)) ^ obj[i];
return hashCode;
}
}
// ...
var hc = ByteArrayEqualityComparer.Default.GetHashCode(data);

EDIT: If you want to validate that the value hasn't changed you should use CRC32.

Producing the same hashcode if 2 array objects contain the same values

As far as I understand the question you should use Enumerable.SequenceEqual in Equals and some kind of aggregation within GetHashCode():

   byte[] extraData = ...

...

public bool Equals(MessageType other) {
...

if (!Enumerable.SequenceEqual(extraData, other.extraData))
return false;

...
}

public override int GetHashCode() {
unchecked { // we don't want IntegerOverflow exceptions to be thrown
int result = ...

...
// let's combine hashes with xor
result ^= extraData == null
? 0
: extraData.Aggerate(0, (s, a) => s ^ a); // ...and aggerate with xor as well

...

return result;
}
}

In case extraData can be quite long (an appalling 1 GB for instance) you may want to restrict the computation to, say, 10 first items:

   result ^= extraData == null 
? 0
: extraData.Take(10).Aggerate(0, (s, a) => s ^ a);


Related Topics



Leave a reply



Submit