来自以下哈希
hash ={"a"=>100,"b"=>200,"c"=>100,"d"=>120,"e" => 400, "f"=>430, "g"=>500}
我想删除所有具有相同“值”或具有50(“值”)差异的对(“key”,“value”)。 例如,a => 100且c =>应该删除100,因为它们具有相同的“值”。并且d => 120也应该被删除,因为100和120之间的差值是20.当差值为30时,也应该删除400和430.
我应该只有
散列[ “b” 的=> 200, “G”=> 500]
上面只是一个例子,实际上,我有33,000个键的哈希值。
答案 0 :(得分:2)
如果k1=>v1
,则要删除一对哈希的键/值对k2=>v2
和(v1-v2).abs <= 50
。这包括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]]]
现在构建一个由要删除的键组成的数组(重复OK)
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"]
拉出要保留的键的值
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}
答案 1 :(得分:1)
试试这个:
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。