2016-03-31 8 views
7

Potrzebuję uzyskać tylko 16 (lub inną małą liczbę) możliwych skrótów z ciągu znaków do kolorowania kontaktów na podstawie nazwy kontaktu.Hash/digest z określoną (małą) ilością wariantów

musiałem postarać się mieszania CRC32, i następnie podjąć pierwszy symbol, który jest hex cyfra:

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

Mam jednak wątpliwości co do dobrej dystrybucji takiej metody. Jak mogę uzyskać małą i określoną ilość wariantów trawionych z ciągu?

Odpowiedz

1

Jeśli głównym problemem jest dobra dystrybucja chciałbym użyć pseudo losową dobry silnik:

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

Nie mogę powiedzieć, jak to porównać do podziału pierwszego char z hash, ale to na pewno działa dobrze dla twoich celów.


Edit: Ponieważ wymaga mieszania, testowałem różne mieszań przeciwko pliku tekstowego 500 losowymi nazwami i znalazł CRC32 mieć najbardziej równomierne. Nie wiem, ile nazw można się spodziewać i jak dobry rozkład jest potrzebna, ale rozwiązanie wydaje się dobrym wyborem do mnie:

<?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); 

wyjściowa:

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 

(standardowa funkcja odchylenie wzięte od this answer.)

Próbowałem również MD5, SHA1 i ostatni znak CRC32. Wszystkie zwrócone odchylenia standardowe około 7, czyniąc pierwszy znak CRC32 zwycięzcą.

+0

Nie, moje zadanie nie jest losowe, ale za każdym razem takie samo (stałe) hash dla tej samej osoby, oparte na nazwie tej osoby. – vatavale

+0

@vatavale Proszę zobaczyć moją edycję. Przetestowałem dystrybucję skrótu. –

+0

Wow! To imponująca odpowiedź. Dziękuję Ci! – vatavale