Skip to content

Instantly share code, notes, and snippets.

@aileron
Created November 13, 2014 02:42
Show Gist options
  • Save aileron/7ad7dffa54a22072de7e to your computer and use it in GitHub Desktop.
Save aileron/7ad7dffa54a22072de7e to your computer and use it in GitHub Desktop.
class Array
def eql_all? &block
block = lambda {|a|a} unless block
max=self.length
i=0
c = block.( self[i] )
n = nil
result = while i+1<max
n=block.(self[i+1])
break false unless c == n
c=n
i+=1
end
result.nil?
end
end
@gogotanaka
Copy link

おおありがとうございます!

eql?の挙動変えるfeatureなのでどちらにせよArray#eql?も変えないといけないですね、

whileで回すよりC層でrb_exec_recursive_pairedというAPIが提供されているので

rb_ary_eql(VALUE ary1, VALUE ary2)
{
    if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse;
    if (rb_block_given_p()) {
          return rb_exec_recursive_paired(rb_yield(ary1), rb_yield(ary2));
    }
    if (ary1 == ary2) return Qtrue;
    if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse;
    if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue;
    return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2);
}

こんな感じがいいかなーと思っています

@aileron
Copy link
Author

aileron commented Nov 13, 2014

結局、func(a) == func(b) を想定するなら
func(a) == func(b) == func(c) 等も存在するだろうから

問題としては、複数の値に、同一の処理を行って比較する事にあるのかなと思ったので

なら arrayに、値の比較の為のブロックを受け付けるメソッドが存在すれば良いかと
思ったので、とりあえずモンキーパッチで試してみた所。

@gogotanaka
Copy link

なるほど、であれば

class Array
  def eql_all?(&block)
    map(&block).uniq.count == 1
  end
end

で良いかもしれませんね、uniqは===比較してくれる気がするので.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment