Ruby:枚举器链

时间:2012-04-14 04:36:09

标签: ruby enumerable

最初我打算做以下事情:

arr = [[1,2],[3,4]]
new_arr = 
arr.map do |sub_arr|
    sub_arr.map do |x|
        x+1
    end
end

p new_arr

输出:

[[2,3],[4,5]]

但后来我试图通过“链接”调查员来缩短它:

arr.map.map{|x| x+1}

然后它会给出错误to_ary method missing

我通过

调试了它
arr.each.each{|x| p x}

输出:

[1,2]
[3,4]

,这是原始数组,只取消了一次。

如何链接两个地图/每个枚举器,以便将枚举器分为2个(或更多)级别?或者它必须在块中?


更新

经过一些搜索,显然链obj.Enumerator.Enumerator.Enumerator...只列举一次obj,只有1级深度。为了更深入,需要阻止。我制定了简单的代码,将字符串转换为块(Proc / Lambda;类似于符号到块但更多地使用;更像是函数语法),以便避免使用块。有人有类似的代码String#to_proc,但我找不到它,x,y中的内容不符合我的口味。我使用$0,$1,$2,...

示例代码(前面的示例将写为):

arr = [[1,2],[3,4]]
new_arr = arr.map(&'[$0+1,$1+1]')
p new_arr

我稍后会将原始代码推送到github。如果你想在此之前看到它,你可以使用聊天与我联系,因为我真的拖延:)

5 个答案:

答案 0 :(得分:3)

听起来像递归的工作:

def zipper(args)
  args[0].respond_to?(:each) ? args.map{|a| zipper(a)} : args.map{|i| i+1}
end

zipper([[1,2],[3,4]])
# => [[2, 3], [4, 5]]

zipper([[[1,2],[3,4]],[5,6]])
# => [[[2, 3], [4, 5]], [6, 7]]

答案 1 :(得分:3)

也许你需要一个map,你只想在叶子上应用:

module Enumerable
  def nested_map &block
    map{|e|
      case e
      when Enumerable
        e.nested_map(&block)
      else
        block.call(e)
      end
    }
  end
end

p [[1,2], [3,4]].nested_map(&:succ)
#=> [[2, 3], [4, 5]]

map仅适用于n级嵌套结构。

module Enumerable
  def deep_map level, &block
    if level == 0
      map(&block)
    else
      map{|e| e.deep_map(level - 1, &block)}
    end
  end
end

p [[1,2], [3,4]].deep_map(1, &:succ)
#=> [[2, 3], [4, 5]]

答案 2 :(得分:2)

arr.map {|x| x.map(&:succ)} #=> [[2, 3], [4, 5]]

答案 3 :(得分:0)

为了通过只编写一次x+1来做到这一点,你需要将它放在一个块中。否则,你可以这样做:

  

new_arr = arr.map {| x,y | [x + 1,y + 1]}

或者,如果你坚持,你可以这样做:

  

new_arr = arr.flatten(1).map {| x | X + 1} .each_slice(2).to_a

答案 4 :(得分:0)

就我个人而言,我会像下面两个选项中的一个一样编写它并完成它:

arr.map { |a| a.map(&:next) } 
#=> [[2, 3], [4, 5]]
arr.map { |x, y| [x.next, y.next] } 
#=> [[2, 3], [4, 5]]