在JavaScript中从字符串数组创建唯一ID?

3
我正在通过javascript进行一些缓存操作。我有一个方法,它接受一个字符串数组并返回处理后的结果。我想从这些字符串中创建一个唯一的ID,并将其用作对象中存储结果的键。这样,缓存中的键将占用尽可能少的内存。
本质上,我想要类似于SHA1的东西,但是适用于javascript。
您有任何想法如何实现这一点吗?
谢谢。
5个回答

3
很不幸,如果不使用数组的全部内容作为键,就没有100%保证独特性的方法。大多数好的非加密哈希只能将冲突减少到一定程度,以便在哈希表中获得良好的性能,但你仍然需要验证整个内容是否匹配,这是接受并提高性能的必要步骤。
即使使用SHA-1或MD5等加密哈希,也可能发生冲突,但在大多数情况下,这种情况极其罕见。如果这样足够好,我会选择SHA-1。否则,将数组转换为字符串用作键,并让JavaScript处理哈希和冲突。
无论如何,你可能会交换性能(JavaScript原生哈希可能比你在JavaScript中编写的任何东西都快得多)和可能的绝对正确性来换取空间。
此外,无论你是自己进行哈希还是让JavaScript进行哈希,都要小心如何将数组转换为字符串,因为简单的连接可能不是唯一的(即使使用分隔符)。

1
根据数组中值的性质,您可能可以想出一些快速且适合您情况的方法。同时,考虑碰撞的概率以及其后果也很重要。由于我们目前没有所有这些信息,因此我只能提供一些起点:
  1. 如果预计字符串的连接是“长”的,则需要使用某种返回较短值的“哈希”。
  2. 您可能不需要加密强度哈希,因此md5或sha1可能过度。
  3. 即使是低技术、快速的哈希,例如(将字符串连接的长度作为int) + '/' + (字符串数量作为int) + '/' + (每个字符串的第一个字符),根据您的预期值,也可能是可以接受的。

最后,这里有一个从C#移植的string.GetHashCode()实现。如果它对.NET足够好,那么对您来说也可能足够好。

var str = "concatenation of all array values";
var hash1 = (5381<<16) + 5381; 
var hash2 = hash1;
var hashPos = 0;
while(hashPos < str.length) { 
    hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ str.charCodeAt(hashPos);
    if( hashPos == str.length - 1) { 
        break;
    }
    hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ str.charCodeAt(hashPos + 1);
    hashPos += 2; 
} 

return hash1 + (hash2 * 1566083941);

绝对是一个有趣的解决方案。我会尝试一下,看看它的效果如何。我同意,事情总是有可能发生冲突的风险,但在我的使用情况中,这种情况非常罕见,因为缓存是通过JavaScript存储在实例变量中的,它对每个用户都是独立的,并且在每个请求时重新加载。 - Binary Logic
返回行应为 hash1 + Math.imul(hash2, 1566083941) | 0,以产生正确的32位输出。 - bryc

1

如果不使用哈希,你将无法得到独特且小的东西。

使用myArray.join() 可能保证唯一性,但可能会消耗大量内存,并遇到无法保证唯一性的边缘情况。

最好的方法是在JavaScript中使用哈希算法的实现。


从技术上讲,根据字符串的不同,myArray.join() 甚至不能保证唯一性。例如,['a', 'b', 'c'].join() === ['a', 'b,c'].join()。如果字符串符合某些特定格式,那么这可能已经足够了(但像你所说的那样,没有节省空间)。 - Matthew Crumley
@Matthew 是的,谢谢你提醒我,我没有考虑到这一点。我会进行更新。 - alex
这是我现在正在做的事情。我使用一个令牌来帮助防止冲突。但正如你所说,有些情况下加入会导致超过5,000个字符的结果。这似乎是一个过长的键长度。 - Binary Logic

0

是的,这就是我想要避免的。那段代码看起来非常繁重。我也觉得使用完整字符串作为键比使用这种方式更有效率。 - Binary Logic

-1
也许是这样的:

var newDate = new Date;
var uid = newDate.getTime();

或者这样:

var uid = Math.random() * Math.pow(10, 17) + Math.random() * Math.pow(10, 17) + Math.random() * Math.pow(10, 17) + Math.random() * Math.pow(10, 17));

有很多方法可以获得类似唯一标识符的东西,而且由于你正在使用JavaScript进行缓存,所以这变得更加容易。只需要选择最适合你的方法即可。


非常冒险,很可能会在多个用户的情况下生成重复的ID等等... 不是一个好的解决方案。 - Marc B
我还希望根据给定的值返回相同的id。因此引用了Sha1。 - Binary Logic
1
@Marc B:JavaScript并非共享语言,对于多用户也没有问题,这还取决于其深层目的。 - yoda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接