[英]In Ruby, how do I make a hash from an array?
我有一个简单的数组:
arr = ["apples", "bananas", "coconuts", "watermelons"]
我还有一个函数f
,它将对单个字符串输入执行操作并返回一个值。 该操作非常昂贵,因此我想在哈希中记住结果。
我知道我可以用以下方式进行所需的哈希:
h = {}
arr.each { |a| h[a] = f(a) }
我想做的是不必初始化h,这样我就可以编写如下代码:
h = arr.(???) { |a| a => f(a) }
能做到吗?
假设您有一个函数,函数名称为:“ f”
def f(fruit)
fruit + "!"
end
arr = ["apples", "bananas", "coconuts", "watermelons"]
h = Hash[ *arr.collect { |v| [ v, f(v) ] }.flatten ]
会给你:
{"watermelons"=>"watermelons!", "bananas"=>"bananas!", "apples"=>"apples!", "coconuts"=>"coconuts!"}
更新:
如评论中所述,Ruby 1.8.7为此引入了更好的语法:
h = Hash[arr.collect { |v| [v, f(v)] }]
对某些给出的答案做了一些快速,肮脏的基准测试。 (这些发现可能与基于Ruby版本,奇怪的缓存等的发现并不完全相同,但是总体结果将是相似的。)
arr
是ActiveRecord对象的集合。
Benchmark.measure {
100000.times {
Hash[arr.map{ |a| [a.id, a] }]
}
}
基准@ real = 0.860651,@ cstime = 0.0,@ cutime = 0.0,@ stime = 0.0,@ utime = 0.8500000000000005,@ total = 0.8500000000000005
Benchmark.measure {
100000.times {
h = Hash[arr.collect { |v| [v.id, v] }]
}
}
基准@ real = 0.74612,@ cstime = 0.0,@ cutime = 0.0,@ stime = 0.010000000000000009,@ utime = 0.740000000000002,@ total = 0.750000000000002
Benchmark.measure {
100000.times {
hash = {}
arr.each { |a| hash[a.id] = a }
}
}
基准@ real = 0.627355,@ cstime = 0.0,@ cutime = 0.0,@ stime = 0.010000000000000009,@ utime = 0.6199999999999974,@ total = 0.6299999999999975
Benchmark.measure {
100000.times {
arr.each_with_object({}) { |v, h| h[v.id] = v }
}
}
基准@ real = 1.650568,@ cstime = 0.0,@ cutime = 0.0,@ stime = 0.12999999999999998,@ utime = 1.51,@ total = 1.64
仅仅因为Ruby具有表现力和动态性,并不意味着您应该始终寻求最漂亮的解决方案。 基本的每个循环在创建哈希中最快。
h = arr.each_with_object({}) { |v,h| h[v] = f(v) }
我可能会这样写:
h = Hash[arr.zip(arr.map(&method(:f)))]
简单,清晰,明显,说明性。 你还能想要什么?
Ruby 2.6.0通过将一个块传递给to_h
方法来实现较短的语法:
arr.to_h { |a| [a, f(a)] }
我正在按照这篇出色的文章http://robots.thoughtbot.com/iteration-as-an-anti-pattern#build-a-hash-from-an-array中的描述进行操作
array = ["apples", "bananas", "coconuts", "watermelons"]
hash = array.inject({}) { |h,fruit| h.merge(fruit => f(fruit)) }
有关inject
方法的更多信息: http : //ruby-doc.org/core-2.0.0/Enumerable.html#method-i-inject
另一个,恕我直言-
Hash[*array.reduce([]) { |memo, fruit| memo << fruit << f(fruit) }]
将长度用作f()-
2.1.5 :026 > array = ["apples", "bananas", "coconuts", "watermelons"]
=> ["apples", "bananas", "coconuts", "watermelons"]
2.1.5 :027 > Hash[*array.reduce([]) { |memo, fruit| memo << fruit << fruit.length }]
=> {"apples"=>6, "bananas"=>7, "coconuts"=>8, "watermelons"=>11}
2.1.5 :028 >
除了弗拉多·辛格(Vlado Cingel)的答案(我还不能添加评论,所以我添加了答案)。
注入也可以通过这种方式使用:该块必须返回累加器。 仅块中的分配返回分配的值,并报告错误。
array = ["apples", "bananas", "coconuts", "watermelons"]
hash = array.inject({}) { |h,fruit| h[fruit]= f(fruit); h }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.