I need to convert the string to some form of hash. Is this possible in JavaScript?
I don't use the server-side language, so I can't do that.
#1 building
edit
According to my jsperf test, the acceptable answer is actually faster: http ://jsperf.com/hashcodelordvlad
original
If anyone is interested, this is an improved (faster) version that will fail on older browsers that lack the reduce array feature.
hashCode = function(s){ return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0); }
Single line arrow function version:
hashCode = s => s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)
#2 building
I need a similar (but different) function to generate a unique ID based on the user name and current time. So:
window.newId = -> # create a number based on the username unless window.userNumber? window.userNumber = 0 for c,i in window.MyNamespace.userName char = window.MyNamespace.userName.charCodeAt(i) window.MyNamespace.userNumber+=char ((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()
Generation:
2DVFXJGEKL 6IZPAKFQFL ORGOENVMG ... etc
Edit June 2015: for new code, I use shortid: https : //www.npmjs.com/package/shortid
#3 building
If it's useful for anyone, I'll combine the first two answers into an older browser tolerant version. If you can use reduce, use the quick version; if not, use esmiralha's solution.
/** * @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; }
The usage is like:
var hash = new String("some string to be hashed").hashCode();
#4 building
Note: even if the best 32-bit hash is used, sooner or later conflicts will occur.
Hash conflict probability can be calculated as Approximate ( See here ) This may be higher than intuition suggests:
Assuming a 32-bit hash and K = 10000 items, the probability of collision is 1.2%. For 77163 samples, the probability becomes 50%! ( Calculator ).
I suggest a solution at the bottom.
In response to this question, Which hash algorithm is best for uniqueness and speed? By Ian Boyd In-depth analysis . In short (as I explain), he came to the conclusion that Murmur was the best, followed by FNV-1a.
The Java String.hashCode () algorithm proposed by esmiralha seems to be a variant of DJB2.
- FNV-1a has a better distribution than DJB2, but is slower
- DJB2 is faster than FNV-1a, but tends to produce more collisions
- MurmurHash3 is better and faster than DJB2 and FNV-1a (but the optimized implementation requires more lines of code than FNV and DJB2)
Some benchmarks with larger input strings: http : //jsperf.com/32-bit-hash
When hashing short input strings, the performance of noise decreases relative to DJ2B and FNV-1a: http ://jsperf.com/32-bit-hash/3
So, in general, I would recommend murmur3.
See here for JavaScript implementation: https : //github.com/garycourt/murmurhash-js
If the input string is short and the performance score is more important, use DJB2 (the answer accepted by esmiralha).
If quality and small code size are more important than speed, then I will use this implementation of FNV-1a (based on This code ).
/** * Calculate a 32 bit FNV-1a hash * Found here: https://gist.github.com/vaiorabbit/5657561 * Ref.: http://isthe.com/chongo/tech/comp/fnv/ * * @param {string} str the input value * @param {boolean} [asString=false] set to true to return the hash value as * 8-digit hex string instead of an integer * @param {integer} [seed] optionally pass the hash of the previous chunk * @returns {integer | string} */ function hashFnv32a(str, asString, seed) { /*jshint bitwise:false */ var i, l, hval = (seed === undefined) ? 0x811c9dc5 : seed; for (i = 0, l = str.length; i < l; i++) { hval ^= str.charCodeAt(i); hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); } if( asString ){ // Convert to 8 digit hex string return ("0000000" + (hval >>> 0).toString(16)).substr(-8); } return hval >>> 0; }
Increase collision probability
As stated here , we can use the following techniques to expand the hash bit size:
function hash64(str) { var h1 = hash32(str); // returns 32 bit (as 8 byte hex string) return h1 + hash32(h1 + str); // 64 bit (as 16 byte hex string) }
Use with caution, but do not expect too much.
#5 building
I combined two solutions (user esmiralha and lordvd) to get a function, which should be faster for browsers that support js function reduce() and are still compatible with old browsers:
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); } else { var hash = 0, i, chr, len; if (this.length == 0) return hash; for (i = 0, len = this.length; i < len; i++) { chr = this.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; } };
Example:
my_string = 'xyz'; my_string.hashCode();