From: "小西 弘将" Date: 2005-07-28T11:24:55+09:00 Subject: [ruby-list:40947] Re: オブジェクト配列の単一化は?  小西 弘将です。 >>eql?の再定義がうまくいっていないのでしょうか? > >eql? を再定義した場合は、hash も再定義する必要があります。 > >http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=Object#eql.3f > >というわけで、こんな感じでしょうか。 > >class Hoge > def initialize( n ) > @name = n > end > def eql?( otr ) > @name.eql?( otr.name ) > end > def hash # a.eql?(b) が成り立つときは a.hash == b.hash でないといけない > @name.hash # なので、 @name.hash + 1039 なんてものでも OK ? > end > attr_accessor :name >end > >dat = [ Hoge.new( "hoge" ), > Hoge.new( "hage" ), > Hoge.new( "boke" ), > Hoge.new( "hage" ), > Hoge.new( "boke" ) ] >dat.uniq! > >dat.each do |d| > print d.name,"\n" >end なるほど、うまくいきました。ありがとうございます。 今回はString#hashでうまくいきましたが、この仕様だとHash値の衝突がないよ うに自分でうまく設計しなければならないケースが出てきそうです(レアだとは 思いますが)。 また、2重配列の場合の単一化もきれいにかけそうにないです。 dat = [[0,0,0],[1,1,1],[2,2,2],[1,1,1]] dat.uniq! みたいに書けない上、Array#hash、Array#eql?をこのときだけ変えるというのも スレッドとか考えるとよくないように思えます。 最初uniqもsortやdelete_atと同じ毛色のものと思っていたので、下のように評 価関数をブロック渡しすることでできないかなぁと思ったりもしました。 dat = [[0,0,0],[1,1,1],[2,2,2],[1,1,1]] dat.uniq! do |lhs,rhs| return false if lhs.size != rhs.size for i in (0...lhs.size) return false if lhs[i] != rhs[i] end true end #もちろんサイズが大きくなると遅くなるでしょうが