my fantasy: instant array of AR attributes?

If there's a way to do this, I would be very happy:

let's pretend that I have an array called folks holding several AR objects from a model called People:

folks = [ <AR 1: name => "bob", sex => "m", age => 40>,
<AR 2: name => "sam", sex => "m", age => 7>,
<AR 3: name => "dee", sex => "f", age => 25> ]

What i've always wanted to do was say something like:

folks.names

...and get an array back with ["bob","sam","dee"].

It seems kind of cumbersome to write a loop to do this, especially when RoR is supposed to be all neato and cool. Am I missing something obvious or do I really have to use a loop?

Thanks!

You could go about it a number of ways.

I like this method

folks.collect! { |person| person.name}

Now folks is an array of all of their names…

subimage interactive wrote:

You could go about it a number of ways.

I like this method

folks.collect! { |person| person.name}

Doesn't Rails provide a shortcut:

   folks.collect(&:name)

?

Hi --

subimage interactive wrote:

You could go about it a number of ways.

I like this method

folks.collect! { |person| person.name}

Doesn't Rails provide a shortcut:

folks.collect(&:name)

?

Yes, and actually the thing that makes it work (Symbol#to_proc) is in
1.9:

$ /usr/local/lib/ruby-cvs/bin/ruby -ve 'puts [1,2,3].map(&:to_f)'
ruby 1.9.0 (2006-12-09 patchlevel 0) [i686-linux]
1.0
2.0
3.0

David

Even shorter:

names = folks.collect(&:name)

-christos

I love it! My fantasy has come true. Anyone got a handle on what the & does? I knew about collect but it alters the original array, which I want to avoid (shuold’ve said that in my first email, sorry).

Thanks to everyone for the suggestions!

-Jason

Hi --

Even shorter:

names = folks.collect(&:name)

I love it! My fantasy has come true. Anyone got a handle on what the & does? I knew about collect but it alters the original array, which I want to avoid (shuold've said that in my first email, sorry).

collect (aka map) doesn't alter the original array, unless you use the
! version (collect! or map!). I think one of the people who replied
did use that, but Christos's version doesn't.

The & introduces a lambda (an anonymous function, technically an
instance of Proc), to be used as the code block to go with the method
call. For example, look at this:

   array = [1,2,3,4,5]
   array.map {|e| e * 10 } # [10,20,30,40,50]

and now with a separate lambda:

   lam = lambda {|e| e * 10 }
   array.map &lam # [10,20,30,40,50]

The reason it works with &:name is that Rails has a to_proc conversion
method for symbols. That method gets called automatically when the &
is applied. When you do &:name, you get a lambda that, if you wrote
it out by hand, would look like this:

   lambda {|e| e.send(:name) }

So -- the net effect of all of this is that this:

   folks.collect(&:name)

calls collect on folks, with a code block (a lambda) that performs the
function of calling the "name" method on each element in folks. The
result is a second, result array, consisting of all the names.

David