开发者

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 0s! 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 Methods 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:

  1. Write your own smart Array#to_proc: array.map(&[:[], 0]). Pretty ugly in this particular case.

  2. 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".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜