Я ищу переносимый алгоритм для создания хэш-кода для двоичных данных. Ни один из двоичных данных не является очень длинным - я Avro
-кодирую ключи для использования в kafka.KeyedMessages
- мы, вероятно, говорим о длине от 2 до 100 байтов, но большинство ключей находятся в диапазоне от 4 до 8 байтов.
На данный момент мое лучшее решение - преобразовать данные в шестнадцатеричную строку, а затем выполнить hashCode
этого. Я могу заставить это работать как в Scala, так и в JavaScript. Предполагая, что я определил b: Array[Byte]
, Scala выглядит так:
b.map("%02X" format _).mkString.hashCode
В JavaScript
он немного сложнее - к счастью, кто-то уже портировал базовый алгоритм хэш-кода на JavaScript. - но суть в том, чтобы создать строку Hex
для представления двоичных данных, я могу гарантировать, что алгоритм хеширования работает с теми же входными данными.
С другой стороны, мне нужно создать объект, вдвое превышающий размер оригинала, просто для создания хэш-кода. К счастью, большая часть моих данных крошечные, но все же - должен быть лучший способ сделать это.
Вместо того, чтобы заполнять данные в виде шестнадцатеричного значения, я предполагаю, что вы можете просто преобразовать двоичные данные в строку, чтобы строка имела то же количество байтов, что и двоичные данные. Это будет все искаженное, больше управляющих символов, чем печатных символов, но тем не менее это будет строка. Но есть ли у вас проблемы с переносимостью? Порядок байтов, Unicode и т. Д.
Между прочим, если вы так далеко прочитали и еще этого не знаете - вы не можете просто сделать:
val b: Array[Byte] = ...
b.hashCode
К счастью, я знал это еще до того, как начал, потому что натолкнулся на это на ранней стадии.
Обновить
Основываясь на первом полученном ответе, на первый взгляд кажется, что java.util.Arrays.hashCode(Array[Byte])
подойдет. Однако, если вы проследите путь javadoc, вы увидите, что это алгоритм, стоящий за ним, который основан на объединенном алгоритме для List и алгоритме для byte
.
int hashCode = 1;
for (byte e : list) hashCode = 31*hashCode + (e==null ? 0 : e.intValue());
Как видите, все, что он делает, это создает Long
, представляющий значение. В какой-то момент число становится слишком большим, и оно замыкается. Это не очень удобно. Я могу заставить его работать для JavaScript, но вам нужно импортировать npm
модуль long
. Если да, то это будет выглядеть так:
function bufferHashCode(buffer) {
const Long = require('long');
var hashCode = new Long(1);
for (var value of buff.values()) { hashCode = hashCode.multiply(31).add(value) }
return hashCode
}
bufferHashCode(new Buffer([1,2,3]));
// hashCode = Long { low: 30817, high: 0, unsigned: false }
И вы действительно получаете те же результаты, когда данные оборачиваются, вроде как, хотя я не знаю почему. В Scala:
java.util.Arrays.hashCode(Array[Byte](1,2,3,4,5,6,7,8,9,10))
// res30: Int = -975991962
Обратите внимание, что результатом является Int. В JavaScript:
bufferHashCode(new Buffer([1,2,3,4,5,6,7,8,9,10]);
// hashCode = Long { low: -975991962, high: 197407, unsigned: false }
Поэтому я должен взять low
байт и игнорировать high
, но в остальном я получаю те же результаты.