假设我有:
a = Hash.new
a['google.com'][:traffic] << 50
a['google.com'][:traffic] << 20
a['google.com'][:popular] << 1
a['google.com'][:popular] << 2
3a['yahoo.com'][:anythinghere] << 3
需要产生这样的东西:
a = { 'google.com' => {traffic: [50,20], popular: [1,2]}, 'yahoo.com' => { anythinghere: [3,4] } }
到目前为止,我已尝试过这种方式,希望能产生这样的结果:
a= Hash.new(Hash.new(Array.new))
例如,a['google.com']
将生成新哈希,而a['google.com'][:anythinghere]
将生成新数组。但是,当我尝试执行上述插入时,a
为空?不知道发生了什么,我很确定我在这里缺少一些基本的东西。看看:
a = stats = Hash.new(Hash.new(Array.new))
a['google.com'][:traffic] << 5
a['google.com'][:traffic] << 6
p a['google.com'][:traffic] #=> [5,6]
p a['google.com'] #=> empty hash???
p a #=> empty hash???
答案 0 :(得分:4)
您获得此意外行为的原因是,当您将默认值作为new
的参数传递给哈希时,一个对象是默认值用于所有密钥。例如:
s = "but"
a = Hash.new(s)
a['x'].concat 't'
puts a['y']
# butt
puts s
# butt
这是有道理的,因为Ruby使用指针传递对象,因此无论何时获得默认值,它都是指向您传递的原始对象的指针。
要解决此问题,您可以在块中设置默认值。这样,Hash每次需要默认值时都必须重新评估该块:
a = Hash.new { "but" }
a['x'].concat 't'
puts a['x']
# but
puts a.size
# 0
接下来的问题是,当Ruby获得默认值时,它不会将其分配给任何键。这就是为什么在访问前一个示例中的密钥后哈希的大小仍为0的原因。这个问题也可以解决,因为Ruby将哈希本身和缺少的键提供给默认值块,所以我们可以在那里进行分配:
a = Hash.new { |hash, key| hash[key] = "but" }
a['x'].concat 't'
puts a['x']
# butt
puts a['y']
# but
puts a.size
# 2
答案 1 :(得分:1)
您可以使用以下行:Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = [] } }
a = Hash.new { |h, k| h[k] = Hash.new { |h2, k2| h2[k2] = [] } }
a['google.com'][:traffic] << 50
a['google.com'][:traffic] << 20
a['google.com'][:popular] << 1
a['google.com'][:popular] << 2
a['yahoo.com'][:anythinghere] << 3
a
# => {"google.com"=>{:traffic=>[50, 20], :popular=>[1, 2]}, "yahoo.com"=>{:anythinghere=>[3]}}
我发现提供给Hash.new
的块有点乱,所以它可以像这样清理:
def Hash.default_set(&block)
Hash.new { |h, k| h[k] = block.call }
end
a = Hash.default_set { Hash.default_set { [] } }
# ...
答案 2 :(得分:0)
另一种方式:
<强>代码强>
def hashify(arr)
arr.each_with_object({}) do |e,h|
*hash_keys, array_key, value = e
g = hash_keys.reduce(h) { |g,k| g[k] ||= {} }
(g[array_key] ||= []) << value
end
end
<强>实施例强>
a = [['google.com', :traffic, 50],
['google.com', :traffic, 20],
['google.com', :popular, 1],
['google.com', :popular, 2],
['yahoo.com', :anythinghere, 3],
['yahoo.com', :anythinghere, 4]]
hashify(a)
#=> {"google.com"=>{:traffic=>[50, 20],
# :popular=>[1, 2]},
# "yahoo.com"=>{:anythinghere=>[3, 4]}}
a = [['google.com', :traffic, 50],
['google.com', :traffic1, :cat, :dog, 20],
['google.com', :traffic1, :cat, :dog, 30],
['google.com', :popular, 1],
['google.com', :popular, 2],
['yahoo.com', :anythinghere, 3],
['yahoo.com', :anythinghere, 4]]
hashify(a)
#=> {"google.com"=>{:traffic=>[50], :traffic1=>{:cat=>{:dog=>[20, 30]}},
# :popular=>[1, 2]},
# "yahoo.com"=>{:anythinghere=>[3, 4]}}