Friday, December 26, 2008

Why dont Array.first() and Array.last() accept blocks?

It would be nice if Array.first and Array.last took block parameters. That way you could get the first or last item in the array based on a block condition. Example:

>> [1,2,3].first {|x| x > 1 }
=> 2

As most things in ruby, its super easy to implement:

class Array
def first
each do |x|
return x if !block_given? || yield(x)
end
end
def last
reverse_each do |x|
return x if !block_given? || yield(x)
end
end
end

a = [1,2,3]
puts a.first # => 1
puts a.first {|x| x>1 } # => 2
puts a.last # => 3
puts a.last {|x| x<2 } # => 1


Heres how to implement this with the MRI interpreter. (Not as beautiful)

static VALUE
rb_ary_first(argc, argv, ary)
int argc;
VALUE *argv;
VALUE ary;
{
if (argc == 0) {
if (rb_block_given_p()) {
long i;
RETURN_ENUMERATOR(ary, 0, 0);
for (i=0; ilen; i++) {
if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) {
return RARRAY(ary)->ptr[i];
}
}
return Qnil;
} else {
if (RARRAY(ary)->len == 0) return Qnil;
return RARRAY(ary)->ptr[0];
}
}
else {
return ary_shared_first(argc, argv, ary, Qfalse);
}
}

No comments: