Я хочу сгенерировать в Ruby тот же хэш-код, возвращаемый методом Java String.hashCode. Какой подход был бы самым элегантным? Реализация хеш-кода Java String описана здесь: http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#hashCode%28%29
Это моя версия. Он делает то же самое, что и javascript hashCode. Обратите внимание, что упаковка и распаковка 32-битного конвертирования:
def hash_code(str)
str.each_char.reduce(0) do |result, char|
[((result << 5) - result) + char.ord].pack('L').unpack('l').first
end
end
Вот простая реализация.
def jhash(str)
result = 0
mul = 1
max_mod = 2**31 - 1
str.chars.reverse_each do |c|
result += mul * c.ord
result %= max_mod
mul *= 31
end
result
end
И некоторые образцы пробега
jhash("aa")
3104
jhash("")
0
jhash("polygenelubricants") #Java returns -2147483648
1283535072
Обратите внимание, что реализация java возвращает int, который имеет ширину 32 бит (31 бит для unsigned). Реализация Java hashcode также может возвращать отрицательные значения. Эта реализация не будет имитировать поведение отрицательного хэш-кода java. Вместо этого он будет возвращать целое число от 0 до 2 ** 31-1 (Integer.MAX_VALUE)
Это пример, который возвращает тот же результат, что и hashCode() в java
TWO_31 = 2 ** 31
TWO_32 = 2 ** 32
def java_hash_code(str)
size = str.size
hash = 0
str.chars.each_with_index do |ch, i|
hash += ch.ord * (31 ** (size-(i+1)))
hash = hash % TWO_32 - TWO_31
end
hash
end