-
-
Save hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0 to your computer and use it in GitHub Desktop.
/** | |
* Returns a hash code for a string. | |
* (Compatible to Java's String.hashCode()) | |
* | |
* The hash code for a string object is computed as | |
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] | |
* using number arithmetic, where s[i] is the i th character | |
* of the given string, n is the length of the string, | |
* and ^ indicates exponentiation. | |
* (The hash value of the empty string is zero.) | |
* | |
* @param {string} s a string | |
* @return {number} a hash code value for the given string. | |
*/ | |
hashCode = function(s) { | |
var h = 0, l = s.length, i = 0; | |
if ( l > 0 ) | |
while (i < l) | |
h = (h << 5) - h + s.charCodeAt(i++) | 0; | |
return h; | |
}; |
> hashCode('') | |
0 | |
> hashCode('Hello') | |
69609650 |
Alternative using arrays:
function hashCode(str) {
return Array.from(str)
.reduce((s, c) => Math.imul(31, s) + c.charCodeAt(0) | 0, 0)
}
Thank you.
hashCode = function(s) {
var h = 0, i = s.length - 1;
while (i >= 0)
h = (h << 5) - h + s.charCodeAt(--i) | 0;
return h;
};
One less local variable and one less if.
the last char will be ignored and in a last iteration you try to take charCode for -1
hashCode = function(s) {
var h = 0, i = s.length;
while (i > 0) {
h = (h << 5) - h + s.charCodeAt(--i) | 0;
}
return h;
};
Using
let
function hashCode(s) { for(let i = 0, h = 0; i < s.length; i++) h = Math.imul(31, h) + s.charCodeAt(i) | 0; return h; }Since you've changed
var
tolet
, variableh
now must be declared outside the for loop.function hashCode(s) { let h; for(let i = 0; i < s.length; i++) h = Math.imul(31, h) + s.charCodeAt(i) | 0; return h; }
For s.length === 0 :)
function hashCode(s) {
let h=0;
for(let i = 0; i < s.length; i++)
h = Math.imul(31, h) + s.charCodeAt(i) | 0;
return h;
}
A comprehensive list of general purpose hash functions and their implementations can found here:
Alternative using arrays:
function hashCode(str) { return Array.from(str) .reduce((s, c) => Math.imul(31, s) + c.charCodeAt(0) | 0, 0) }
A one liner version
const hashCode = (str) => [...str].reduce((s, c) => Math.imul(31, s) + c.charCodeAt(0) | 0, 0)
Source: https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
/**
* @see http://stackoverflow.com/q/7616461/940217
* @return {number}
*/
String.prototype.hashCode = function(){
if (Array.prototype.reduce){
return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);
}
var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
var character = this.charCodeAt(i);
hash = ((hash<<5)-hash)+character;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
Use:
console.log(
String('[').hashCode(),
String('a').hashCode(),
String(']').hashCode(),
String('[a]').hashCode(),
String('[a]').hashCode()
)
// Output:
// 91 97 93 90551 90551
/**
* Returns a UUIDv4 as string
*
* @returns {string}
*/
generateUuid = () => {
return (
String('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx')
).replace(/[xy]/g, (character) => {
const random = (Math.random() * 16) | 0;
const value = character === "x" ? random : (random & 0x3) | 0x8;
return value.toString(16);
});
};
generateUuid()
Here's even faster implementation of the original using ES6 reduce.
This code is similar to what @jschirrmacher have suggested hence not a new implementation.
But from my small limited testing it seems to be faster than original while loop and for loop.
function hashCode(s) {
return [...s].reduce(
(hash, c) => (Math.imul(31, hash) + c.charCodeAt(0)) | 0,
0
);
}
Tested in Chrome (112.0 v)
- Original (while loop): 2.40087890625 ms
- Modified (for loop): 3.412109375 ms
- New (reduce): 1.150146484375 ms
@Super-Chama you copied the answer from @4nte ...
@martin-juul no, look again.
So no one else wastes time looking for the difference (there is none):
const hashCode = (str) => [...str].reduce((s, c) => Math.imul(31, s) + c.charCodeAt(0) | 0, 0)
function hashCode(s) {
return [...s].reduce(
(hash, c) => (Math.imul(31, hash) + c.charCodeAt(0)) | 0, // extraneous ( )
0
);
}
@ngp33 there's at least 5 differences. my point is, i didn't copy anyone's code. I would happily give credit if i did. I saw the original implementation and thought reduce will be nicer than loop and faster. so i wrote my own, tested with console.time
and posted for anyone coming into this thread. but i'll update my comment as precaution
@martin-juul What's your point? this whole thread is entirely derivative, and there's only so many ways to continually add a sequence of numbers and multiply by 31 in a loop. We're talking about one line of code basically. People modified my code and I did not care, because it's far too basic.
@Super-Chama Hmm, that version appears to in fact be noticeably slower (than my for
loop version at least). It could be that either the spread operator or reduce
is slowing things down in batch operations, not sure which. See benchmark: https://jsbench.me/vcljn1em32
I tried to use this method in my project but it didn't seem to spread out adjacent inputs very well:
for (let i = 0; i < 1000; i++) {
console.log(hashCode("" + i));
}
48 49 50 51 52 53 54 55 56 57 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700
I found this awesome single file module that works great though:
https://github.com/garycourt/murmurhash-js
Just FYI, another take on the same problem here, with both an old Java-style hash and with a version of @bryc's excellent, more modern cyrb53 hash:
https://gist.github.com/jlevy/c246006675becc446360a798e2b2d781
What about a hashCode of an object in JS? Maybe that can only happen in C/C++ land.
You can use JSON.stringify(object) to turn it into a string first, then encode, then when you decode, turn it back into an object with JSON.parse()
@ORESoftware you may be interested in https://github.com/puleos/object-hash