Как я могу создать уникальные идентификаторы в Perl? - PullRequest
2 голосов
/ 30 июня 2009

Я создаю файлово-ориентированную базу данных результатов некоторых тестов, выполненных различными пользователями. Для этого мне нужно создать уникальный идентификатор для каждой записи в базе данных. Идентификаторы должны удовлетворять следующим требованиям:

  • Идентификаторы должны быть довольно маленькими (максимум 6 символов)
  • Для каждого тестового примера и пользовательской комбинации каждый раз должен генерироваться один и тот же идентификатор

Я попробовал простую хеш-функцию BKDR со значением семени 31 и использовал функцию ord () следующим образом:

@chars = split(//,$hash_var);

$hash = 0;
$seed = 31;

foreach $char ( @chars ) {
   if( $char !~ m/\d/ ) {
       $hash = ( $seed * $hash ) + ord( $char );
   }  
   else {
       $hash = ( $seed * $hash ) + $char ;
   }
}

$hash = ( $hash & 0x7FFFFFFF ) % 1000;
$hash = "$chars[0]$chars[$#chars]$hash" ;

Это иногда приводит к одним и тем же результатам для различных комбинаций, т. Е. Уникальности не наблюдается. Есть ли другой способ сделать это? Помогает ли изменение начального значения достичь уникальности?

Ответы [ 3 ]

5 голосов
/ 30 июня 2009

Есть ли у вас более 256 пользователей и / или более 65536 тестовых случаев на пользователя? Если нет, вы можете просто индексировать пользователей с 0 .. 255 и тестовые случаи с 0 .. 65535 и кодировать его как строку шестнадцатеричных цифр, чтобы было достаточно шести символов.

Если у вас больше пользователей или тестовых случаев, чем это, я бы снова проиндексировал пользователей и тестовые случаи, а затем объединил бы их в 32-разрядное целое число, которое на самом деле занимало бы всего 4 байта и было бы тривиально для реализации, но немного сложнее для людей .

В любом случае, я предполагаю, что вы получили имя пользователя и информацию о тестовом наборе. Просто сохраните два связанных хэша: %users и %cases, чтобы отобразить пользователей и контрольные примеры в их индексы.

3 голосов
/ 30 июня 2009

Частично ваша проблема может заключаться в том, что вы используете математику с плавающей запятой, а BKDR почти наверняка требует целочисленную математику. Вы можете исправить эту ошибку, сказав

my @chars = split(//,$hash_var);

my $hash = 0;
my $seed = 31;

for my $char ( @chars ) {
   use integer;
   if( $char !~ m/\d/ ) {
       $hash = ( $seed * $hash ) + ord( $char );
   }  
   else {
       $hash = ( $seed * $hash ) + $char ;
   }
}

$hash = ( $hash & 0x7FFFFFFF ) % 1000;
$hash = "$chars[0]$chars[$#chars]$hash" ;

Еще один трюк, который может помочь, - это использование символов, отличных от первого и последнего. Если первый и последний символы имеют тенденцию быть одинаковыми, они не добавляют уникальности хешу.

Возможно, вы также захотите использовать лучшую хеш-функцию, такую ​​как MD5 (доступна в Digest :: MD5), и обрезать результат до желаемого размера. Однако тот факт, что вы вообще используете хеш, означает, что вы рискуете столкнуться.

1 голос
/ 30 июня 2009

Если у вас мало пользователей / тестовых случаев, простого решения, подобного этому, может быть достаточно. Вам нужно добавить ограничение (и, возможно, упаковать целое число при его сохранении).

vinko@parrot:~# more hash.pl
use strict;
use warnings;

my %hash;
my $count = 0;

sub getUniqueId {

        my $_user = shift;
        my $_test = shift;
        my $val;

        my $key = $_user."|".$_test;
        if (defined $hash{$key}) {
                $val = $hash{$key};
        } else {
                $hash{$key} = $count;
                $val = $count;
                $count = $count + 1;
        }
        return $val;
}

my @users = qw{ user1 user2 user3 user4 user5 user3 user5 };
my @testcases = qw{ test1 test2 test3 test1 test1 };

for my $user (@users) {
        for my $test (@testcases) {
                print "$user $test: ".getUniqueId($user,$test)."\n";
        }
}
vinko@parrot:~# perl hash.pl
user1 test1: 0
user1 test2: 1
user1 test3: 2
user1 test1: 0
user1 test1: 0
user2 test1: 3
user2 test2: 4
user2 test3: 5
user2 test1: 3
user2 test1: 3
user3 test1: 6
user3 test2: 7
user3 test3: 8
user3 test1: 6
user3 test1: 6
user4 test1: 9
user4 test2: 10
user4 test3: 11
user4 test1: 9
user4 test1: 9
user5 test1: 12
user5 test2: 13
user5 test3: 14
user5 test1: 12
user5 test1: 12
user3 test1: 6
user3 test2: 7
user3 test3: 8
user3 test1: 6
user3 test1: 6
user5 test1: 12
user5 test2: 13
user5 test3: 14
user5 test1: 12
user5 test1: 12
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...