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: