您可以使用Ruby的块速记来调用诸如数组访问器之类的方法吗?

时间:2018-10-29 04:56:53

标签: ruby

我习惯于缩短

some_array.map { |e| e.to_s }

some_array.map(&:to_s)

有没有一种方法可以缩短

some_array_of_arrays.map { |e| e[4] }

类似于

some_array_of_arrays.map(&:[4])

很显然,我已经尝试了最后一个示例,但是它不起作用。理想情况下,该解决方案应推广到其他“奇怪格式”的方法调用,例如[]

我对任何Rails / ActiveSupport解决方案都不感兴趣。假定有某种解决方案,则仅使用纯Ruby。

2 个答案:

答案 0 :(得分:5)

您可以使用 Proc

> a = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14]]
> third_elem = Proc.new {|x| x[2]}
> a.map(&third_elem)
#> [3, 7, 11, nil] 

OR

> a.map &->(s) {s[2]}
#=> [3, 7, 11, nil] 

答案 1 :(得分:4)

然后,您可以构建它。它不那么优雅,但是...

class Call
  def self.[](name, *args)
    self.new(name, *args)
  end

  def initialize(name, *args)
    @proc = Proc.new do |obj|
      obj.send(name, *args)
    end
  end

  def to_proc
    @proc
  end
end

fourth = Call.new(:[], 3)
[[1,2,3,4,5],[6,7,8,9,10]].map(&fourth)           # => [4, 9]
# or equivalently
[[1,2,3,4,5],[6,7,8,9,10]].map(&Call.new(:[], 3)) # => [4, 9]
[[1,2,3,4,5],[6,7,8,9,10]].map(&Call[:[], 3])     # => [4, 9]

如果要专门针对索引,甚至可以简化为:

class Index
  def self.[](*args)
    self.new(*args)
  end

  def initialize(*args)
    @proc = Proc.new do |obj|
      obj[*args]
    end
  end

  def to_proc
    @proc
  end
end

[[1,2,3,4,5],[6,7,8,9,10]].map(&Index[3])     # => [4, 9]

或者,更简短一点,如@muistooshort在评论中所展示的,如果您不想拥有一个专门针对它的完整课程:

index = ->(*ns) { ->(a) { a[*ns] } }
[[1,2,3,4,5],[6,7,8,9,10]].map(&index[3])     # => [4, 9]