times 方法 returns nil with hash
times method returns nil with hash
我所做的是从散列中随机获取 2 个值并将它们与键匹配。我的代码有两个随机值,那部分效果很好。但是当涉及到 p hash[m] 时,我预计它会打印 hash 的键,而不是 returns nil。例如:
我们的随机值为“cat”和“ocean”。该程序使用时间方法自行选择此值。
所以当 m = "cat" 时 hash[m] 应该是 "dog",但它是 nil。同样的事情也适用于“海洋”。所以我有两个零值。为什么?我该如何解决这个问题并获得正确的密钥?
hash = { "foo" => "bar", "cat" => "dog", "ear" => "nose", "ocean" => "sea"}
value = hash.values
2.times do
m = value[rand(value.size)]
p hash[m] #Erroneous part
end
Select 通过随机选择 键 随机 key/value 对,因为这样更容易:
my_hash = { "foo" => "bar", "cat" => "dog", "ear" => "nose", "ocean" => "sea"}
my_keys = my_hash.keys
2.times do
rand_key = my_keys[rand(my_keys.size)]
rand_val = my_hash[rand_key]
puts "#{rand_key} => #{rand_val}"
end
我的理解是,给定一个散列并希望随机 select 两个值,然后识别与这些值关联的键。例如,如果
hash = { :a=>1, :b=>2, :c=>3 }
值为
values = hash.values
#=> [1, 2, 3]
在此示例中,值是唯一的。稍后我将解决值不唯一的一般情况(例如,{ :a=>1, :b=>2, :c=>3, :d=>2 }
)。
如果要随机 select 两个值,我们会写
random_values = values.sample(2)
#=> [2, 1]
用统计术语来说,Array#sample samples without replacement(见第 3 段)。相比之下,
random_values = 2.times.map { values[rand(values.size)] }
对两个值 进行替换 采样,因此 random_values
可能等于,例如 [2, 2]
.
一旦获得random_values
(假设[2, 1]
),有两种方法可以获得关联的键:
第一个如下
associated_keys = random_values.map { |v| hash.key(v) }
#=> [:b, :a]
尽管构建一个将键与随机值相关联的散列可能更有用:
random_values.each_with_object({}) { |v,h| h[v] = hash.key(v) }
#=> {2=>:b, 1=>:a}
参见Hash#key. The second way is to use Hash#invert:
hsaH = hash.invert
#=> { 1=>:a, 2=>:b, 3=>:c }
然后我们简单计算:
hsaH.values_at(*random_values)
#=> [:b, :a]
或
hsaH.slice(*random_values)
#=> {2=>:b, 1=>:a}
参见 Hash#values_at and Hash#slice。
现在考虑值不唯一的一般情况。假设
hash = { :a=>1, :b=>2, :c=>3, :d=>2 }
其中键 :b
和 :d
具有相同的值。
values = hash.values
#=> [1, 2, 3, 2]
那么如果我们写
random_value = values.sample(2)
我们可以获得random_values #=> [2, 2]
。这可能是允许的,但如果需要两个 unique 值,我们会写
unique_values = values.uniq
#=> [1, 2, 3]
random_values = unique_values.sample(2)
#=> [3, 2]
选择使用 values
还是 unique_values
取决于应用程序。无论如何,如果结果是[3,2]
,使用上面的第一种方法我们得到
keys = hash.keys
#=> [:a, :b, :c, :d]
associated_keys = random_values.map { |v| hash.key(v) }
#=> [:c, :b]
然而,这可能并不令人满意,因为它取决于 hash
键的顺序。假设:
hash = { :a=>1, :d=>2, :c=>3, :b=>2 }
在这种情况下我们得到不同的答案:
keys = hash.keys
#=> [:a, :d, :c, :b]
associated_keys = random_values.map { |v| hash.key(v) }
#=> [:c, :d]
同样,
{ :a=>1, :b=>2, :c=>3, :d=>2 }.invert
#=> {1=>:a, 2=>:d, 3=>:c}
{ :a=>1, :d=>2, :c=>3, :b=>2 }.invert
#=> {1=>:a, 2=>:b, 3=>:c}
2
的值不同。
对于一般情况(同样,取决于应用程序),我们可能会考虑编写以下内容。
hash = { :a=>1, :d=>2, :c=>3, :b=>2 }
values_to_keys = hash.each_with_object({}) do |(k,v),h|
(h[v] ||= []) << k
end
#=> {1=>[:a], 2=>[:d, :b], 3=>[:c]}
然后
values = hash.values
random_values = values.sample(2)
#=> [3, 1]
random_values.map { |v| [v, values_to_keys[v].shift] }
#=> [[3, :c], [1, :a]]
第二个例子:
random_values = values.sample(2)
#=> [2, 2]
random_values.map { |v| [v, values_to_keys[v].shift] }
#=> [[2, :d], [2, :b]]
注意在values_to_keys
的计算中,(h[v] ||= []) << k
展开为
(h[v] = h[v] || []) << k
所以如果 h
没有密钥 v
,这就变成了
(h[v] = nil || []) << k
(h[v] = []) << k
导致 h[v]
被设置为一个空数组,它被返回,然后 k
被附加到该空数组。相比之下,如果 h
已经有一个键 v
,
(h[v] = h[v] || []) << k
#=> (h[v] = h[v]) << k
#=> h[v] << k
我所做的是从散列中随机获取 2 个值并将它们与键匹配。我的代码有两个随机值,那部分效果很好。但是当涉及到 p hash[m] 时,我预计它会打印 hash 的键,而不是 returns nil。例如:
我们的随机值为“cat”和“ocean”。该程序使用时间方法自行选择此值。
所以当 m = "cat" 时 hash[m] 应该是 "dog",但它是 nil。同样的事情也适用于“海洋”。所以我有两个零值。为什么?我该如何解决这个问题并获得正确的密钥?
hash = { "foo" => "bar", "cat" => "dog", "ear" => "nose", "ocean" => "sea"}
value = hash.values
2.times do
m = value[rand(value.size)]
p hash[m] #Erroneous part
end
Select 通过随机选择 键 随机 key/value 对,因为这样更容易:
my_hash = { "foo" => "bar", "cat" => "dog", "ear" => "nose", "ocean" => "sea"}
my_keys = my_hash.keys
2.times do
rand_key = my_keys[rand(my_keys.size)]
rand_val = my_hash[rand_key]
puts "#{rand_key} => #{rand_val}"
end
我的理解是,给定一个散列并希望随机 select 两个值,然后识别与这些值关联的键。例如,如果
hash = { :a=>1, :b=>2, :c=>3 }
值为
values = hash.values
#=> [1, 2, 3]
在此示例中,值是唯一的。稍后我将解决值不唯一的一般情况(例如,{ :a=>1, :b=>2, :c=>3, :d=>2 }
)。
如果要随机 select 两个值,我们会写
random_values = values.sample(2)
#=> [2, 1]
用统计术语来说,Array#sample samples without replacement(见第 3 段)。相比之下,
random_values = 2.times.map { values[rand(values.size)] }
对两个值 进行替换 采样,因此 random_values
可能等于,例如 [2, 2]
.
一旦获得random_values
(假设[2, 1]
),有两种方法可以获得关联的键:
第一个如下
associated_keys = random_values.map { |v| hash.key(v) }
#=> [:b, :a]
尽管构建一个将键与随机值相关联的散列可能更有用:
random_values.each_with_object({}) { |v,h| h[v] = hash.key(v) }
#=> {2=>:b, 1=>:a}
参见Hash#key. The second way is to use Hash#invert:
hsaH = hash.invert
#=> { 1=>:a, 2=>:b, 3=>:c }
然后我们简单计算:
hsaH.values_at(*random_values)
#=> [:b, :a]
或
hsaH.slice(*random_values)
#=> {2=>:b, 1=>:a}
参见 Hash#values_at and Hash#slice。
现在考虑值不唯一的一般情况。假设
hash = { :a=>1, :b=>2, :c=>3, :d=>2 }
其中键 :b
和 :d
具有相同的值。
values = hash.values
#=> [1, 2, 3, 2]
那么如果我们写
random_value = values.sample(2)
我们可以获得random_values #=> [2, 2]
。这可能是允许的,但如果需要两个 unique 值,我们会写
unique_values = values.uniq
#=> [1, 2, 3]
random_values = unique_values.sample(2)
#=> [3, 2]
选择使用 values
还是 unique_values
取决于应用程序。无论如何,如果结果是[3,2]
,使用上面的第一种方法我们得到
keys = hash.keys
#=> [:a, :b, :c, :d]
associated_keys = random_values.map { |v| hash.key(v) }
#=> [:c, :b]
然而,这可能并不令人满意,因为它取决于 hash
键的顺序。假设:
hash = { :a=>1, :d=>2, :c=>3, :b=>2 }
在这种情况下我们得到不同的答案:
keys = hash.keys
#=> [:a, :d, :c, :b]
associated_keys = random_values.map { |v| hash.key(v) }
#=> [:c, :d]
同样,
{ :a=>1, :b=>2, :c=>3, :d=>2 }.invert
#=> {1=>:a, 2=>:d, 3=>:c}
{ :a=>1, :d=>2, :c=>3, :b=>2 }.invert
#=> {1=>:a, 2=>:b, 3=>:c}
2
的值不同。
对于一般情况(同样,取决于应用程序),我们可能会考虑编写以下内容。
hash = { :a=>1, :d=>2, :c=>3, :b=>2 }
values_to_keys = hash.each_with_object({}) do |(k,v),h|
(h[v] ||= []) << k
end
#=> {1=>[:a], 2=>[:d, :b], 3=>[:c]}
然后
values = hash.values
random_values = values.sample(2)
#=> [3, 1]
random_values.map { |v| [v, values_to_keys[v].shift] }
#=> [[3, :c], [1, :a]]
第二个例子:
random_values = values.sample(2)
#=> [2, 2]
random_values.map { |v| [v, values_to_keys[v].shift] }
#=> [[2, :d], [2, :b]]
注意在values_to_keys
的计算中,(h[v] ||= []) << k
展开为
(h[v] = h[v] || []) << k
所以如果 h
没有密钥 v
,这就变成了
(h[v] = nil || []) << k
(h[v] = []) << k
导致 h[v]
被设置为一个空数组,它被返回,然后 k
被附加到该空数组。相比之下,如果 h
已经有一个键 v
,
(h[v] = h[v] || []) << k
#=> (h[v] = h[v]) << k
#=> h[v] << k