具有确定(少量)变体的哈希/消化

时间:2016-03-31 08:14:36

标签: javascript php hash colors

我需要根据联系人姓名从字符串中获取16个(或其他少量)可能的哈希值,用于颜色编码联系人。

我曾尝试获取crc32哈希,然后取第一个符号,即十六进制数字:

$contact = 'Robin Hood';
$colors = [
     '0' => 'F8BBD0',
     '1' => 'E1BEE7',
     ...
     'e' => 'D7CCC8',
     'f' => 'CFD8DC',
];
$firstLetter = hash('crc32', $contact)[0];
return '#' . $colors[$firstLetter];

然而,我怀疑这种方法的良好分布。如何从字符串中获取小的和确定数量的变体?

1 个答案:

答案 0 :(得分:1)

如果您的主要关注点是良好的分布,我会使用一个好的伪随机引擎:

$colorKey = bin2hex(openssl_random_pseudo_bytes(1))[0];
return '#' . $colors[$colorKey];

我不能说这与哈希的第一个字符的分布相比如何,但这肯定适用于您的目的。

编辑:由于您需要哈希,我针对500个随机名称的文本文件测试了各种哈希值,并发现crc32具有最均匀的分布。我不知道你期望有多少名字或者你需要多好的分发,但你的解决方案对我来说似乎是一个不错的选择:

<?php
function sd_square($x, $mean) { return pow($x - $mean,2); }

function sd($array) {
    return sqrt(array_sum(array_map("sd_square", $array, array_fill(0,count($array), (array_sum($array) / count($array)) ) ) ) / (count($array)-1) );
}

$crcColorCounts = array_fill_keys(range(0, 15), 0);
$file = fopen('random_names.txt', 'r');
while ($contact = fgets($file)) {
    $hash = hash('crc32', $contact);
    $letter = $hash[0];
    $crcColorCounts[hexdec($letter)]++;
}
fclose($file);
print_r($crcColorCounts);
echo 'Standard deviation: ', sd($crcColorCounts);

输出:

Array
(
    [0] => 32
    [1] => 26
    [2] => 33
    [3] => 31
    [4] => 40
    [5] => 29
    [6] => 33
    [7] => 20
    [8] => 33
    [9] => 30
    [10] => 39
    [11] => 27
    [12] => 36
    [13] => 33
    [14] => 29
    [15] => 30
)
Standard deviation: 4.8815127436755

(标准偏差函数取自this answer。)

我也尝试过MD5,SHA1和CRC32的最后一个字符。所有返回的标准偏差都在7左右,使CRC32的第一个字符串成为赢家。