ruby在哈希中删除相同值的多个键

时间:2014-04-21 20:27:38

标签: ruby hash

来自以下哈希

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个键的哈希值。

2 个答案:

答案 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

k1k2被添加到要删除的键数组中(块变量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}

答案 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。