如何使用Ruby中的map重构每个函数?

时间:2014-06-05 20:49:32

标签: ruby-on-rails ruby

我有一个构建哈希的循环,用于选择字段。目的是最终得到一个哈希:

{ object.id => "object name", object.id => "object name" }

使用:

@hash = {}
loop_over.each do |ac|
  @hash[ac.name] = ac.id
end

我认为map方法适用于这种情况,但需要一些帮助来理解它以及它是如何工作的。 map是重构此each循环的正确方法吗?

7 个答案:

答案 0 :(得分:4)

这样的数据转换更适合each_with_object

@hash = loop_over.each_with_object({}) { |ac, h| h[ac.name] = ac.id }

如果你的大脑告诉你使用map,但你不想要一个数组作为结果,那么你通常想要使用each_with_object。如果您想要将块的返回值反馈回自身,那么您需要inject,但在这种情况下,inject需要块中有趣且外观;h

@hash = loop_over.inject({}) { |h, ac| h[ac.name] = ac.id; h }
# -------------------- yuck -----------------------------^^^

人工返回值的存在是您想要使用each_with_object的信号。

答案 1 :(得分:3)

尝试:

Hash[loop_over.map { |ac| [ac[:name], ac[:id]] }]

或者如果你在Ruby 2上运行:

loop_over.map { |ac| [ac[:name], ac[:id]] }.to_h

答案 2 :(得分:1)

@hash = Hash[loop_over.map { |ac| {ac.name => ac.id} }.map(&:flatten)]

根据评论中的建议编辑,这是一个更简单的解决方案。

@hash = Hash[ loop_over.map { |ac| [ac.name, ac.id] } ]

答案 3 :(得分:1)

您可以简单地通过注入一个空白的新Hash并执行您的操作来执行此操作:

loop_over.inject({}){ |h, ac| h[ac.name] = ac.id; h }

Ruby FTW

答案 4 :(得分:0)

没有地图不是正确的工具。

map的一般用例是接受数组,对每个元素执行操作,并吐出(可能)新数组(散列映射)相同长度,单个元素修改。

以下是地图的示例

x = [1, 2, 3, 4].map do |i|
  i+1 #transform each element by adding 1
end

p x # will print out [2, 3, 4, 5]

您的代码:

@hash = {}
loop_over.each do |ac|
  @hash[ac.name] = ac.id
end

这个例子没有错。您正在遍历列表,并按照您的意愿完全填充哈希表。

答案 5 :(得分:0)

Ruby 2.1.0引入了生成哈希的全新方法:

h = { a: 1, b: 2, c: 3 }
h.map { |k, v| [k, v+1] }.to_h # => {:a=>2, :b=>3, :c=>4}

答案 6 :(得分:0)

我会选择inject版本,但在块中使用update以避免容易错过(因此容易出错);h后缀:

@hash = loop_over.inject({}) { |h, ac| h.update(ac.name: ac.id) }