ruby - times 方法返回 nil 和 hash
问题描述
我所做的是从哈希中获取随机 2 个值并将它们与键匹配。我的代码有两个随机值,那部分效果很好。但是当涉及到 p hash[m] 时,我希望它会打印散列的键,而不是返回 nil。例如 :
我们的随机值是“cat”和“ocean”。该程序使用 times 方法自行选择此值。
所以当 m = "cat" hash[m] 应该是 "dog",但它是 nil。“海洋”也是如此。所以我有两个 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
解决方案
我的理解是给你一个哈希值,并希望随机选择两个值,然后识别与这些值关联的键。例如,如果
hash = { :a=>1, :b=>2, :c=>3 }
值是
values = hash.values
#=> [1, 2, 3]
在此示例中,值是唯一的。稍后我将讨论值不唯一的一般情况(例如,{ :a=>1, :b=>2, :c=>3, :d=>2 }
)。
如果要随机选择两个值,我们会写
random_values = values.sample(2)
#=> [2, 1]
在统计术语中,Array#sample样本没有替换(参见第 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}
请参阅哈希#key。第二种方法是使用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 = { :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_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
's 键的顺序。认为:
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
已经有 key v
,
(h[v] = h[v] || []) << k
#=> (h[v] = h[v]) << k
#=> h[v] << k
推荐阅读
- eclipse - 如何在 intellij 中运行预构建 gradle java 项目
- android-studio - Android Studio Quickboot/Snapshot 不支持错误?
- typescript - 如何获取typegoose类模型接口
- python - Python 内置的 max() 函数被程序中稍后出现的同名变量所遮蔽
- json - 通过改造(gson)从json对象中只获取一个参数
- python - 根据条件从字符串中删除空格
- google-cloud-platform - 数据集无效
- android - 如何使 recyclerview 的卡片按钮点击一个单独的事件而不是卡片点击事件本身
- java - java - 如何使用java将集合文档的字段值作为Firestore中的值分配给另一个集合文档字段?
- android - 有时 RxJava onError 不会捕获异常