Лучший способ сравнить два хэша хэшей? - PullRequest
0 голосов
/ 09 января 2012

Прямо сейчас у меня есть два хэша хэшей: 1, который я создал, анализируя файл журнала, и 1, который я извлекаю из SQL. Мне нужно сравнить их, чтобы узнать, существует ли запись из файла журнала уже в базе данных. Сейчас я перебираю каждый элемент, чтобы сравнить их:

foreach my $i(@record)
{
    foreach my $a(@{$data})
    {
        if ($i->{port} eq $a->{port} and $i->{name} eq $a->{name})
        {
            print "match found $i->{name}, updating record in table\n";
        }
        else
        {
            print "no match found for $tableDate $i->{port} $i->{owner} $i->{name} adding record to table\n";
            executeStatement("INSERT INTO client_usage (date, port, owner, name, emailed) VALUES (\'$tableDate\', \'$i->{port}\', \'$i->{owner}\', \'$i->{name}\', '0')");

        }
    }

}

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

Ответы [ 2 ]

2 голосов
/ 09 января 2012

У вас есть более чем хэш хэшей.У вас есть два списка, и каждый элемент в каждом списке содержит хэш хэшей.Таким образом, вы должны сравнить каждый элемент в списке с каждым элементом в другом списке.Ваш алгоритм эффективности O 2 - не потому, что это хеш хешей, а потому, что вы сравниваете каждую строку в одном списке с каждой строкой в ​​другом списке.

Возможно ли этопросмотреть ваши списки и превратить их в хэш с ключами порта и имени?Таким образом, вы просматриваете каждый список один раз, чтобы создать хэш-индекс, а затем один раз просматриваете его, чтобы выполнить сравнение.

Например, чтобы создать хэш из записи:

my %record_hash;
foreach my $record_item (@record) {
   my $name = $record_item->{name};
   my $data = $record_item->{data}
   my $record_hash{$name:$data} = \$record_item  #Or something like this...
}

Далее, вы сделаете то же самое для списка data :

my %data_hash;
foreach my $data_item (@{$data}) {
   my $name = $data_item->{name};
   my $data = $data_item->{data}
   my $data_hash{$name:$data} = \$data_item  #Or something like this...
}

Теперь вы можете просмотреть только что созданный хэш всего один раз:

foreach my $key (keys %record_hash) {
   if (exists $data_hash{$key}) {
       print "match found $i->{name}, updating record in table\n";
   }
   else {
      print "no match found for $tableDate $i->{port} $i->{owner} $i->{name} adding record to table\n";
      executeStatement("INSERT INTO client_usage (date, port, owner, name, emailed) VALUES (\'$tableDate\', \'$i->{port}\', \'$i->{owner}\', \'$i->{name}\', '0')");

   }
}
* 1017Допустим, у вас есть 1000 элементов в одном списке и 500 элементов в другом.Ваш оригинальный алгоритм должен был бы повторяться 500 * 1000 раз (полмиллиона раз).Создав индексный хеш, вы должны выполнить цикл 2 (500 + 1000) раз (примерно 3000 раз).

Другая возможность: поскольку вы уже используете базу данных SQL, почему бы не сделать все это в виде запроса SQL.То есть не берите записи.Вместо этого просмотрите ваши данные, и для каждого элемента данных извлеките запись.Если запись существует, вы обновляете ее.Если нет, вы создаете новый.Это может быть даже быстрее, потому что вы не превращаете все это в список, чтобы превратить его в хеш.

Есть способ связать базы данных SQL напрямую с хешами.Это может быть хорошим вариантом.

Используете ли вы Perl-DBI ?

0 голосов
/ 09 января 2012

Как насчет использования Data :: Difference:

use Data:Difference qw(data_diff);

my @diff = data_diff(\%hash_a, \%hash_b);

@diff = (
    { 'a' => 'value', 'path' => [ 'data' ] }, # exists in 'a' but not in 'b'
    { 'b' => 'value', 'path' => [ 'data' ] }, # exists in 'b' not in 'a'
);
...