【问题标题】:Can you use Ruby's block shorthand to call a method like the array accessor?你可以使用 Ruby 的块简写来调用像数组访问器这样的方法吗?
【发布时间】:2018-10-29 04:56:52
【问题描述】:

我习惯了可以缩短

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,假设有某种解决方案。

【问题讨论】:

标签: ruby


【解决方案1】:

你可以使用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] 

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

【讨论】:

  • 我认为问题的精神是找到一种比.map { |e| e[4] } 更方便的方法,但我认为这是我们将得到的最接近的方法。
【解决方案2】:

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

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 在 cmets 中展示的那样,如果你不想有一个专门的完整课程:

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

【讨论】:

  • 您可以将Index 替换为index = ->(n) { ->(a) { a[n] } } 并说array_of_arrays.map(&index[3])
  • @muistooshort 太短了! :D 很好,虽然它不适用于子序列(而我的 &Index[1, 3] 有效)。
猜你喜欢
  • 1970-01-01
  • 2018-11-08
  • 2013-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多