trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

C#の二次元配列でHashSet

ソース

public class hash2d : IEquatable<hash2d>
{
    public long[,] array2d;
    public hash2d(long[,] a)
    {
        array2d = new long[a.GetLength(0), a.GetLength(1)];
        Array.Copy(a, array2d, a.Length);
    }
    public override bool Equals(object obj) => Equals(obj as hash2d);
    public bool Equals(hash2d other)
    {
        return other != null && this.array2d.Cast<long>().SequenceEqual(other.array2d.Cast<long>());
    }
    public override int GetHashCode()
    {
        return (int)array2d.Cast<long>().Aggregate(0L ,(acc, i) => unchecked(acc * 457 + i * 389));
    }
}

使い方&結果

var h1 = new hash2d(new long[2, 2] { { 1, 2 }, { 3, 4 } });
var h2 = new hash2d(new long[2, 2] { { 1, 2 }, { 3, 4 } });
var h3 = new hash2d(new long[2, 2] { { 5, 6 }, { 7, 8 } });
var h4 = new hash2d(new long[2, 2] { { 2, 1 }, { 3, 4 } });
WriteLine("HashCode");
WriteLine("\th1:"+h1.GetHashCode());
WriteLine("\th2:"+h2.GetHashCode());
WriteLine("\th3:"+h3.GetHashCode());
WriteLine("\th4:"+h4.GetHashCode());

WriteLine("\nEquals");
WriteLine("\th1-h2:"+h1.Equals(h2));
WriteLine("\th1-h3:"+h3.Equals(h1));
WriteLine("\th1-h4:"+h4.Equals(h1));

var hs = new HashSet<hash2d>();
hs.Add(h1);
WriteLine("\nHashSet");
WriteLine("\th1-h2:"+hs.Contains(h2));
WriteLine("\th1-h3:"+hs.Contains(h3));
WriteLine("\th1-h4:"+hs.Contains(h4));

//結果
HashCode
  h1:-1363972990
  h2:-1363972990
  h3:1443673746
  h4:1322759658

Equals
  h1-h2:True
  h1-h3:False
  h1-h4:False

HashSet
  h1-h2:True
  h1-h3:False
  h1-h4:False
参考

stackoverflow.com

小ネタ

longの二次元配列をintの一次元配列にする
var a = new long[2, 2] { { 1, 2 }, { 3, 4 } };
. var b = a.Cast<long>().Select(i => (int)i).ToArray();
> b
int[4] { 1, 2, 3, 4 }

参考

ni4muraano.hatenablog.com

oita.oika.me

二次元配列をコピー
    public long[,] array2d;
    public hash2d(long[,] a)
    {
        array2d = new long[a.GetLength(0), a.GetLength(1)];
        Array.Copy(a, array2d, a.Length);
    }

参考

www.atmarkit.co.jp

Dictionary,HashSetの仕組み

(1)まずGetHashCodeメソッドで、ハッシュ値が同じかを調べる
(2)ハッシュ値が同じときは、Equalsメソッドでオブジェクトの同値性を調べる
1と2が同じだったら、同じと判断する。

mocotan.hatenablog.com

A hash code is a numeric value that is used to insert and identify an object in a hash-based collection such as the Dictionary<TKey,TValue> class, the Hashtable class, or a type derived from the DictionaryBase class.

docs.microsoft.com

Dictionary<TKey,TValue> requires an equality implementation to determine whether keys are equal. You can specify an implementation of the IEqualityComparer generic interface by using a constructor that accepts a comparer parameter; if you do not specify an implementation, the default generic equality comparer EqualityComparer.Default is used.

docs.microsoft.com

適当に確認

EqualsTrueを返すようにする

public bool Equals(hash2d other)
{
    return true;
}
HashCode
  h1:-1363972990
  h2:-1363972990
  h3:1443673746
  h4:1322759658

Equals
  h1-h2:True
  h1-h3:True
  h1-h4:True

HashSet
  h1-h2:True
  h1-h3:False
  h1-h4:False

GetHashCodeが同じ値を返すようにする

public override int GetHashCode()
{
    return 0;
}
HashCode
  h1:0
  h2:0
  h3:0
  h4:0

Equals
  h1-h2:True
  h1-h3:False
  h1-h4:False

HashSet
  h1-h2:True
  h1-h3:False
  h1-h4:False

両方

public bool Equals(hash2d other)
{
    return true;
}
public override int GetHashCode()
{
    return 0;
}
HashCode
  h1:0
  h2:0
  h3:0
  h4:0

Equals
  h1-h2:True
  h1-h3:True
  h1-h4:True

HashSet
  h1-h2:True
  h1-h3:True
  h1-h4:True

背景

螺旋本の8パズルやってたら配列でHashSet使いたくなった。螺旋本終わったらAtCoder再開する。

先日蟻本買ったのだけど。昨日今日あたりからセールしてるっぽい。ぽい・・・。