特定用途向け C# 用 tuple クラス
まだ、実際に使ったわけではないけど。
わざわざ struct かくほどでもないなというときに、pair クラスは重宝されます。しかし、いちいち型を書くのがメンドクサイと、OCaml の tuple が欲しくなります。特に、特定用途で引数をすべて tuple にして、hash のキーとして突っ込むときなど、pair を入れ子にしていると死にそうになります。しかし、これと同等の物を作ろうとすると、型推論のない言語では結局 pair の入れ子と大差ないコストがかかって、やな感じになります。そこで型チェックはあきらめて、hash 値だけとれればいいや思ったとき、配列を使えばいいじゃんという結論に至ったわけですね。
class Tuple { private object array; public Tuple(object array) { this.array = array; } public static implicit operator Tuple(object[] os) { return new Tuple(os); } public override bool Equals(object o) { return this.Equals*1 return false; return true; } public override int GetHashCode() { int h = 0; foreach (object o in array) h ^= o.GetHashCode(); return h; } }
わりといい加減ですが、この程度でも十分使えるでしょう。C# は int も object のサブクラスとして扱えるので、int や string の混ざった配列も渡せます。問題は、コンテナ系クラスの Equals メソッドが、値比較してくれないみたいで、ちょっとがっかり。implicit operator は object[] から Tuple へ暗黙の型変換です。別になくてもいいですが、少し手間が省けます。下のように動きます。
class Test { static void Main() { Tuple t = new object{1, 2, "a"}; Tuple s = new object{1, 2, "a"}; Tuple u = new object[]{1, 3, "a"}; Console.WriteLine(t == s); Console.WriteLine(t.Equals(s)); Console.WriteLine(t == u); Console.WriteLine(t.Equals(u)); Dictionarydic = new Dictionary (); dic[t] = 1; dic[u] = 2; dic[s] = 3; Console.WriteLine(dic[t]); } }
実行結果
$ ./a False True False False 3
当然ですが、C++ ではこれはできません。Java もできますかね? できました。Object[] に整数リテラルを入れられるのは、Tiger からかな?
import java.util.HashMap; class Tuple { Object array; public Tuple(Object array) { this.array = array; } public boolean equals(Object o) { Tuple t = (Tuple)o; for (int i = 0; i < array.length; i++) if (!array[i].equals(t.array[i])) return false; return true; } public int hashCode() { int h = 0; for (Object o: array) h ^= o.hashCode(); return h; } public static void main(String args) { Tuple t = new Tuple(new Object{1, 2, "a"}); Tuple s = new Tuple(new Object{1, 2, "a"}); Tuple u = new Tuple(new Object{1, 3, "a"}); System.out.println(t.equals(s)); System.out.println(t.equals(u)); HashMaphash = new HashMap (); hash.put(t, 1); hash.put(u, 2); hash.put(s, 3); System.out.println(hash.get(t)); } }
*1:Tuple)o); } public bool Equals(Tuple o) { for (int i = 0; i < array.Length; i++) if (!array[i].Equals(o.array[i]