Търся преносим алгоритъм за създаване на хешкод за двоични данни. Нито една от двоичните данни не е много дълга -- аз съм Avro
-кодиращи ключове за използване в kafka.KeyedMessages
-- вероятно говорим за дължина от 2 до 100 байта, но повечето от ключовете са в диапазона от 4 до 8 байта.
Досега най-доброто ми решение е да конвертирам данните в шестнадесетичен низ и след това да направя hashCode
от това. Мога да накарам това да работи както в Scala, така и в JavaScript. Ако приемем, че съм дефинирал b: Array[Byte]
, Scala изглежда така:
b.map("%02X" format _).mkString.hashCode
В JavaScript
е малко по-сложно -- за щастие някой вече е пренесъл основния алгоритъм на hashCode към JavaScript -- но смисълът е да мога да създам низ Hex
за представяне на двоичните данни, мога да гарантирам, че алгоритъмът за хеширане работи със същите входове.
От друга страна, трябва да създам обект два пъти по-голям от оригинала, само за да създам hashCode. За щастие повечето ми данни са малки, но все пак -- трябва да има по-добър начин за това.
Вместо да допълвате данните като шестнадесетична стойност, предполагам, че можете просто да принудите двоичните данни в низ, така че низът да има същия брой байтове като двоичните данни. Всичко ще бъде изкривено, повече контролни знаци, отколкото знаци за печат, но въпреки това ще бъде низ. Срещате ли обаче проблеми с преносимостта? Endian-ness, 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
, но иначе получавам същите резултати.