Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Substitute the GetHashCode() Method of System.Drawing.Point

System.Drawing.Point has a really, really bad GetHashCode method if you intend to use it to describes 'pixels' in a Image/Bitmap: it is just XOR between the X and Y coordinates.

So for a image with, say, 2000x2000 size, it has an absurd number of colisions, since only the numbers in the diagonal are going to have a decent hash.

It's quite easy to create a decent GetHashCode method using unchecked multiplication, as some people already mentioned here.

But what can I do to use this improved GetHashCode method in a HashSet? I know I could create my own class/struct MyPoint and implement it using this improved methods, but then I'd break all other pieces of code in my project that use a System.Drawing.Point.

Is it possible to "overwrite" the method from System.Drawing.Point using some sort of extension method or the like? Or to "tell" the HashSet to use another function instead of the GetHashCode?

Currently I'm using a SortedSet<System.Drawing.Point> with a custom IComparer<Point> to store my points. When I want to know if the set contains a Point I call BinarySearch. It's faster than a HashSet<System.Drawing.Point>.Contains method in a set with 10000 colisions, but it's no as fast as HashSet with a good hash could be.

like image 957
Trauer Avatar asked May 26 '15 21:05

Trauer


1 Answers

You can create your own class that implements IEqualityComparer<Point>, then give that class to the HashSet constructor.

Example:

public class MyPointEqualityComparer : IEqualityComparer<Point>
{
    public bool Equals(Point p1, Point p2)
    {
        return p1 == p2; // defer to Point's existing operator==
    }

    public int GetHashCode(Point obj)
    {
        return /* your favorite hashcode function here */;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create hashset with custom hashcode algorithm
        HashSet<Point> myHashSet = new HashSet<Point>(new MyPointEqualityComparer());

        // Same thing also works for dictionary
        Dictionary<Point, string> myDictionary = new Dictionary<Point, string>(new MyPointEqualityComparer());
    }
}
like image 54
Jared Moore Avatar answered Oct 10 '22 07:10

Jared Moore