カスタムデータ構造のハッシュコードを作成するにはどうすればよいですか?

私は、特定のシステムに従ってオブジェクトの位置を定義するカスタムの「座標」データ構造を作成しました。

座標は次のように定義されます。

public class Coordinate
{
    public int X;
    public int Y;
    private int face;
    public int Face
    {
        get { return face; }
        set
        {
            if (value >= 6 | value < 0)
                throw new Exception("Invalid face number");
            else
                face = value;
        }
    }
    private int shell;
    public int Shell
    {
        get { return shell; }
        set
        {
            if (value < 0)
                throw new Exception("No negative shell value allowed");
            else
                shell = value;
        }
    }

    public Coordinate(int face, int x, int y, int shell)
    {
        this.X = x;
        this.Y = y;
        this.face = face;
        this.shell = shell;
    }

    public static Coordinate operator +(Coordinate a, Coordinate b)
    {
        return new Coordinate(a.Face + b.Face, a.X + b.X, a.Y + b.Y, a.Shell + b.Shell);
    }

    public override bool Equals(object obj)
    {
        Coordinate other = (obj as Coordinate);
        if (other == null)
            return false;
        else
            return (Face == other.Face && Shell == other.Shell && X == other.X && Y == other.Y);
    }
}

要約すると、int Face(0〜5)、int X、int Y、およびint Shellが含まれています。 X、Y、およびShellはすべて0以下(下限を含む)にバインドされています。

私はハッシュコードで全く経験がありません。私はそれらを比較して、彼らが等しいかどうかを調べる必要があります。私はこれを試した:

private const int MULTIPLIER = 89;

[...]

int hashCode = 1;
hashCode = MULTIPLIER * hashCode + obj.X.GetHashCode();
hashCode = MULTIPLIER * hashCode + obj.Y.GetHashCode();
hashCode = MULTIPLIER * hashCode + obj.Face.GetHashCode();
hashCode = MULTIPLIER * hashCode + obj.Shell.GetHashCode();
return hashCode;

Google検索で見つけたものを外に出す。しかし、このメソッドを使ってコードをコンパイルしようとすると、ビルドが完了しないので、衝突に陥ることはありません。おそらく座標の束を考えていろいろな種類の不器用なループに遭うかもしれません。

申し訳ありませんが、この質問はかなり基本的ですが、何らかの理由で私は困惑しています。私はちょうどそれが衝突しないようにこのハッシュコードを書く方法のアドバイスを探しています。

6
msdn.microsoft.com/ en-us/library /&hellip; - "派生クラスは、一意のハッシュコードを返す実装でGetHashCodeをオーバーライドする必要があります。"
追加された 著者 Matt Fenwick,
@IlianPinzon - 良い、私は混乱していたので間違っていたことがうれしいです。それをクリアしていただきありがとうございます!
追加された 著者 Matt Fenwick,
ハッシュコードが衝突しても問題はありません。衝突を起こさないことが望ましいですが、必要ではありません(数学的にも不可能です)。
追加された 著者 Jon,
@MattFenwickピジョンホールの原理のために、ほとんどの型のためのユニークなハッシュコードのようなものはありません。*その記事は少し不正確です。彼らは後続バージョンでその行を削除しました。 * - int.GetHashCode()はおそらくそれぞれの番号に対して一意です。
追加された 著者 Ilian Pinzon,

2 答え

これが最良の方法ではない場合でも、それは十分なアプローチになります。

public override int GetHashCode()
{
   return string.Format("{0}-{1}-{2}-{3}", X, Y, Face, Shell).GetHashCode();
}

Update: Take a look at this article: http://ericlippert.com/2011/02/28/guidelines-and-rules-for-gethashcode/

11
追加された
最初に各intを文字列に変換する必要があるため、文字列のハッシュ計算でさらなるコストがかかるため、この答えはスケーラブルなコードを記述する必要がある場合は非常に非効率です。複数のintフィールドを効率的にハッシュするには、ここで私の答えをチェックしてください: stackoverflow.com/a/34006336/1911540
追加された 著者 Special Sauce,
これは本当によかった、ありがとう。私は100000、10000、1000、1を乗算してこれを取得しようとしましたが、これはもっとクリーンで拡張性があります。
追加された 著者 A-Type,
さて、それはまだ構築されません...私はこのハッシュコードを保持し、何か別の何かをしているかどうかを確認するためにいくつかのユニットテストを行います。
追加された 著者 A-Type,
私は "まだビルドされていない"と言っていたはずです。コンパイラエラーはありません。ゲームはちょうどハッシュコードを使用するループで立ち往生します。
追加された 著者 A-Type,
私は、コードをよりスマートにして、何かが働いているかどうかを私に教えてくれるブーリアンを使用していたはずだが、私は例外を使っていた。例外は、プログラムの初期化をクロールに遅らせることでした。この減速が以前に現れなかったという事実は、以前は事が間違っていたことを実証し、私は実現しなかった。ご協力いただきありがとうございます;私のルームメートは、値で比較するために、構造体がハッシュコードを操作するよりも優れていることを思い出させました。しかし、あなたの方法もうまくいくでしょう。私は何かを学びました!
追加された 著者 A-Type,

基本的には、ハッシュコード関数を書くときは、次のことを確認する必要があります:

  • 失効したハッシュコードがない(つまり、ハッシュコードが生成された後にオブジェクトの状態を変更しないでください。再生成した場合、ハッシュコードが変更されます)。
  • 等しい値を持つオブジェクトは同じハッシュコードを返します
  • 同じオブジェクトが常に同じハッシュコードを返します(変更されていない場合)。 - 確定的

また、次のような場合には大変ですが、必要ではありません。

  • ハッシュコードが可能な値に均等に分散している(ソース:ウィキペディア

異なるオブジェクトが異なるハッシュコードを返すようにする必要はありません 。それはHashtablesのようなもののパフォーマンスを低下させる可能性があるので(あなたがたくさんの衝突を持っているならば)ただ眉をひそめるだけです。

しかし、あなたのハッシュコード関数が一意の値を返すようにしたい場合は、完璧なハッシング

2
追加された