ruby 在哈希中删除相同的值多个键
Posted
技术标签:
【中文标题】ruby 在哈希中删除相同的值多个键【英文标题】:ruby remove same value multiple keys in hash 【发布时间】:2014-06-05 23:48:11 【问题描述】:来自以下哈希
hash ="a"=>100,"b"=>200,"c"=>100,"d"=>120,"e" => 400, "f"=>430, "g"=>500
我想删除所有具有相同“值”或差异为 50(“值”)的对(“键”、“值”)。 例如,a=>100 和 c => 100,应该被删除,因为它们具有相同的“值”。并且 d=>120 也应该被删除,因为 100 和 120 之间的差异是 20。400 和 430 也应该被删除,因为差异是 30。
我应该只有
哈希["b"=>200,"g"=>500]
以上只是一个示例,实际上,我有 33,000 个键的哈希值。
【问题讨论】:
和"e"=>180
意味着生成的哈希应该是空的?
相差50?从什么值?应该保留哪个具有相同值的键?这么多问题...
是的,“e”=>180,表示哈希为空
@squiguy 我编辑了这个问题。我希望它现在清楚
这个问题从我第一次看的时候就真的变了。这完全不是我第一次读到的。
【参考方案1】:
如果(v1-v2).abs <= 50
,一对哈希的键/值对k1=>v1
和k2=>v2
都将被删除。这包括 v1 == v2
的对,因此我们不需要单独考虑后者。为此,我首先构造一个要保留的键数组,然后创建一个由原始哈希中的相应键/值对组成的哈希。
代码
keys_to_keep = hash.keys -
hash.sort_by |_,v| v
.each_cons(2)
.each_with_object([])
|((k1,v1),(k2,v2)),a| a << k1 << k2 if (v1-v2).abs <= 50
keys_to_keep.zip(hash.values_at(*keys_to_keep)).to_h
说明
hash = "a"=>100,"b"=>200,"c"=>100,"d"=>120
按哈希值排序:
b = hash.sort_by |_,v| v
#=> [["a", 100], ["c", 100], ["d", 120], ["b", 200]]
接下来,使用Enumerable#each_cons构造一个包含b
的所有相邻元素对的数组:
c = b.each_cons(2)
#=> #<Enumerator:
# [["a", 100], ["c", 100], ["d", 120], ["b", 200]]:each_cons(2)>
查看这个枚举器的内容:
c.to_a
#=> [[["a", 100], ["c", 100]],
# [["c", 100], ["d", 120]],
# [["d", 120], ["b", 200]]]
现在构建一个由要删除的键组成的数组(重复确定)
d = c.each_with_object([])
|((k1,v1),(k2,v2)),a| a << k1 << k2 if (v1-v2).abs <= 50
#=> ["a", "c", "c", "d"]
要计算 d
,请考虑由枚举器 c
传递给块的第一个值:
k1 => "a"
v1 => 100
k2 => "c"
v2 => 100
自从
(100 - 100).abs <= 50
键 k1
和 k2
被添加到要删除的键数组中(块变量 a
)。传递给块的下一个值是:
k1 => "c"
v1 => 100
k2 => "d"
v2 => 120
自从
(100 - 120).abs <= 50
"c"
和 "d"
键也添加到 a
。第三个值不会向a
添加任何键,因为
(120 - 200).abs > 50
现在使用 set Difference 构造一个要保留的键数组:
e = hash.keys
#=> ["a", "b", "c", "d"]
keys_to_keep = e - d
#=> ["b"]
提取要保留的键的值,使用Hash#values_at:
f = hash.values_at(*keys_to_keep)
#=> [200]
为要保留的键构造一个键/值对数组:
g = keys_to_keep.zip(f)
#=> [["b", 200]]
转换为哈希。
g.to_h # Ruby v.2.0+
#=> "b"=>200
或
Hash[g]
#=> "b"=>200
【讨论】:
【参考方案2】:试试这个:
multiple_values = hash.group_by |k, v| v .select |v, i| i.length > 1 .map |v, i| v
hash.delete_if |k, v| multiple_values.any? |i| v < i + 50 && v > i - 50
第一行为所有值构建一个直方图(按值对条目进行分组),并过滤掉所有只有一个条目的值。 这为我们提供了与多个键关联的所有值的列表。 第二遍删除所有值接近其中一个小于 50 的键。
【讨论】:
你能解释一下吗?我认为它正在构建一个直方图,然后将其中的重复项放入多个值中,但我不确定我是否正确。 @Sqeaky - 你是对的。我试图澄清解释。 @UriAgassi 我已经编辑了我的问题。你能帮我修一下吗?当前解决方案查找重复值,然后使用 +/-50 窗口。在任何情况下,我都需要查看 +/-50。以上是关于ruby 在哈希中删除相同的值多个键的主要内容,如果未能解决你的问题,请参考以下文章