我们可以写一个没有哈希类的哈希吗?



为了解决这个问题,让我们假设我们在 Ruby 中没有hash类。

是否可以在不使用 Ruby 中hash class的情况下创建hash?或者,如果我们没有哈希概念,我们可能会称之为 associative array .

虽然可以使用数组来模拟哈希的行为,但性能会受到影响:

require 'fruity'
CHARS = ('a' .. 'z').to_a
ARY = CHARS.zip(CHARS)
HASH = ARY.to_h
compare do 
  _assoc_a { ARY.assoc('a') }
  _hash_a  { HASH['a']      }
  _hash_m  { HASH['m']      }
  _assoc_m { ARY.assoc('m') }
  _assoc_z { ARY.assoc('z') }
  _hash_z  { HASH['z']      }
end
# >> Running each test 32768 times. Test will take about 3 seconds.
# >> _hash_m is similar to _hash_z (results differ: m vs z)
# >> _hash_z is similar to _hash_a (results differ: z vs a)
# >> _hash_a is faster than _assoc_a by 2x ± 1.0 (results differ: a vs ["a", "a"])
# >> _assoc_a is faster than _assoc_m by 5x ± 1.0 (results differ: ["a", "a"] vs ["m", "m"])
# >> _assoc_m is faster than _assoc_z by 2x ± 0.1 (results differ: ["m", "m"] vs ["z", "z"])

执行反向查找,从第二个元素到第一个元素,或从值到键:

compare do
  _rassoc_a      { ARY.rassoc('a')  }
  _hash_rassoc_a { HASH.rassoc('a') }
  _rassoc_m      { ARY.rassoc('m')  }
  _hash_rassoc_m { HASH.rassoc('m') }
  _rassoc_z      { ARY.rassoc('z')  }
  _hash_rassoc_z { HASH.rassoc('z') }
end
# >> Running each test 32768 times. Test will take about 4 seconds.
# >> _rassoc_a is faster than _hash_rassoc_a by 2x ± 1.0
# >> _hash_rassoc_a is faster than _rassoc_m by 3x ± 1.0 (results differ: ["a", "a"] vs ["m", "m"])
# >> _rassoc_m is similar to _hash_rassoc_m
# >> _hash_rassoc_m is similar to _rassoc_z (results differ: ["m", "m"] vs ["z", "z"])
# >> _rassoc_z is similar to _hash_rassoc_z
对我来说,将哈希

反向查找到键会更慢是有道理的,因为哈希没有针对这些事情进行优化。如果我需要这样做,我会尝试创建一个单独的 Hash 来反转键和值,然后使用它来执行反向查找:

hash = {'a' => 1, 'b' => 2}
reversed_hash = hash.invert # => {1=>"a", 2=>"b"}

如果值是数组或值不唯一,并且有时生成的键使用起来不是很方便,则会中断。

是否可以在不使用 Ruby 中hash class的情况下创建hash?或者,如果我们没有哈希概念,我们可能会称之为 associative array .

答案是肯定的。为什么不会呢?哈希表的概念与任何特定语言无关。

此外,Ruby 是一种图灵完备语言,这意味着你可以用 Ruby 计算所有内容,你也可以用任何其他语言计算。

Rubinius 的 Hash 类是用纯 Ruby 编写的,它显然不能使用 Hash 类,所以很明显可以用纯 Ruby 编写Hash。为什么不会呢?YARV 的 Hash 类是用 C 编写的,JRuby 的 Hash 类是用 Java 编写的,IronRuby 是用 C 编写的,Topaz 是用 RPython 编写的,如果你想用 Ruby 编写一个,你"只是"必须编写与所有类相同的内容,除了用 Ruby 而不是 C、Java、C♯♯ 或 RPython。

(公平地说,Rubinius 的 Hash 实现使用 Tuple ,它部分在 C++ 中实现,但同样,你只需要用 Ruby 重写该代码,瞧,你在 Ruby 中有一个Hash类。

当然可以。

如果您不想经历重新创建自己的哈希类的麻烦,则可以使用 Array 类的assocrassoc方法。请参阅"Ruby 中的关联数组...什么?

例子:

picks = [
 ["AAPL", "buy"],
 ["GOOG", "sell"],
 ["MSFT", "sell"]
]
print picks.assoc("AAPL")
puts #new line 
print picks.rassoc("sell") #gets the first row that contains

输出:

["AAPL", "buy"]
["GOOG", "sell"]

最新更新