是否有declare-update-return模式的抽象?

时间:2013-09-09 21:16:16

标签: ruby design-patterns idiomatic mutation

在ruby中编写带有变异的迭代代码时,我经常发现自己遵循这种模式:

def build_x some_data
  x = [] # or x = {}
  some_data.each do |data|
    x.some_in_place_update! (... data ...)
  end
  x
end

x通常与some_data形状不同,因此简单的map不会。{/ p>

是否有更惯用或更好的方法来编写遵循此模式的代码?


[edit]一个真实的例子:

def to_hierarchy stuff
  h = {}
  stuff.each do |thing|
    path = thing.uri.split("/").drop(4)
    sub_h = h
    path.each do |segment|
      sub_h[segment] ||= {}
      sub_h = sub_h[segment]
    end
    sub_h.merge!(
      data: thing.data,
    )
  end
  h
end

这从thing s的平面列表开始,它具有相关但不同的uri s。它将此平面列表转换为层次结构,对与thing共享相同segment的相关uri进行分组。这遵循我描述的模式:初始化h,循环一些数据并在此过程中改变h,然后在最后吐出h

[edit2]另一个相关的例子

def count_data obj
  i = if obj[:data] then 1 else 0
  obj.each do |k, v|
    i += count_statements v unless :data == k
  end
  i
end

2 个答案:

答案 0 :(得分:1)

您的to_hierarchy示例可以使用each_with_object完成:

def to_hierarchy stuff
  stuff.each_with_object({}) do |thing, h|
    #...
  end
end

each_with_object将额外对象传递给块在迭代完成后返回该对象。

如果您更像传统主义者,可以使用inject

def to_hierarchy stuff
  stuff.inject({}) do |h, thing|
    #...
    h
  end
end

请注意块参数顺序更改,并且块必须返回h,以便inject可以将其反馈到下一个块调用中。

您的一般示例可以写成:

def build_x some_data
  some_data.each_with_object([]) do |data, x|
    x.some_in_place_update! (... data ...)
  end
end

或:

def build_x some_data
  some_data.inject({}) do |x, data|
    x.some_in_place_update! (... data ...)
    x
  end
end

答案 1 :(得分:1)

啊!你想要each_with_object。喜欢这个

def to_hierarchy stuff
  stuff.each_with_object({}) do |thing, h|
    path = thing.uri.split("/").drop(4)
    sub_h = h
    path.each do |segment|
      sub_h[segment] ||= {}
      sub_h = sub_h[segment]
    end
    sub_h.merge!(
        data: thing.data,
    )
  end
end