我有一个构建哈希的循环,用于选择字段。目的是最终得到一个哈希:
{ object.id => "object name", object.id => "object name" }
使用:
@hash = {}
loop_over.each do |ac|
@hash[ac.name] = ac.id
end
我认为map
方法适用于这种情况,但需要一些帮助来理解它以及它是如何工作的。 map
是重构此each
循环的正确方法吗?
答案 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) }