How to access arrays within arrays using Ruby's Symbol#to_proc?
How do you write the fo开发者_开发百科llowing using the Symbol#to_proc
syntax?
[[a,1],[b,2],[c,3]].map { |r| r[0] }
This gives an error that the number of arguments is wrong. But I do not know where to give the index argument.
[[a,1],[b,2],[c,3]].map &:[] # Where to put the index 0 ?
I prefer the first form, and I just want to know how to do it using &:
.
You can't. You can pass only methods without parameters that way. In your case you need to suply 0
as a parameter, which you can only using block syntax.
On the other hand, you can achieve the same using first
method:
[[a,1],[b,2],[c,3]].map(&:first)
edit:
Both Joerg's and tokland's answers inspired me to experiment a little bit. You can actually do something like this:
arr = [[:a, 1], [:b, 2], [:c, 3]]
arr.each_with_object(0).map(&:[])
#=> [:a, :b, :c]
arr.each_with_object(1).map(&:[])
#=> [1, 2, 3]
Symbol#to_proc
takes the first argument to be the receiver and passes on any extra arguments it receives to the method, but in this case it gets passed only one argument, because Enumerable#map
only passes the element as the only argument.
However, if that only argument happens to be an Array
, then we can use the destructuring bind feature of block argument binding! So, we can simply use Enumerable#zip
to zip together our elements with an infinite list of 0
s! This, of course, requires that we use something which has block argument binding semantics, i.e. either a block proper:
[[a,1],[b,2],[c,3]].zip([0].cycle).map {|el, i| el[i]}
or a non-lambda Proc
f = proc {|a, i| a[i] }
[[a,1],[b,2],[c,3]].zip([0].cycle).map(&f)
It does, however, not work with Method
s or lambdas, because those don't have block argument binding semantics, they have method argument binding semantics, thus they don't perform automatic destructuring. Symbol#to_proc
, of course, does a message send, thus ending up invoking a method and not a non-lambda Proc
or a block. That's why this won't work with Symbol#to_proc
.
Short answer: you can't.
Long answer:
Write your own smart
Array#to_proc
:array.map(&[:[], 0])
. Pretty ugly in this particular case.Use Facets map_send:
array.map_send(:[], 0)
(and 3: as Mladen pointed out: array.map(&:first)
, but if you want another index you can't)
Most likely overkill, but for the sake of completeness: you could write your own method like
class Array
def to_proc
->(x) { x[first] }
end
end
and use it like so:
[[a,1],[b,2],[c,3]].map(&[0])
You can read more about this in my blog post "Array#to_proc for hash access".
精彩评论