Сравнение двух ассоциативных массивов

Я начал изучать Perl на прошлой неделе.

У меня есть ассоциативный массив из файла, содержащего «токены» — просто набор чисел. У меня есть еще один ассоциативный массив из базы данных SQL, содержащий «токены».

Я хочу посмотреть, нет ли каких-либо токенов в файле в базе данных. Однако все, что я делаю, кажется, не работает, и я пришел к выводу, что просто запутался.

Я не уверен, что полностью понимаю ассоциативные массивы, но это фрагмент моего кода для хэша файла:

while($row = <FILE>){
    if($row =~ /^000\E/){
        @tmp=split(/\s+/,$row);     
        if($tmp[1] ne "Unassigned"){
            $tokenfile{$tmp[0]} = $tmp[1] . " " . $tmp[2];
        }
    }
}

$tmp[1] + $tmp[2] — это имя и фамилия. Позже я сравниваю имена, чтобы увидеть, равны ли они друг другу. Однако я хочу сравнить $tmp[0] - токен. Это хэш SQL:

while(@rows = $sth->fetchrow_array){
    ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwnam("\L$rows[1]\E");
    $gcos =~ s/,.*//;
    if(!defined($gcos)){
        $missing++;
        $tokendb{$rows[0]} = $rows[1];
    }
    else{
        $tokendb{$rows[0]} = $gcos;
    }
}

$rows[0] — это токен.

Я предполагал, что буду использовать два цикла foreach, например:

foreach $token (keys(%tokendb)) {
    foreach $token2(keys(%tokenfile)){
        if($token ne $token2){
            print "$token2 NOT IN DATABASE\n";
        }
    }
}

Но это дает мне результат много значений, которые все еще находятся в базе данных.

Я хотел бы получить некоторые подсказки относительно того, почему это не работает. Очень расстраивает, потому что я знаю, что это так просто, но мой мозг сегодня не работает так хорошо (несмотря на то, что мне 21 день рождения :|).


person abstrakt    schedule 26.02.2013    source источник
comment
Что означает \E в /^000\E/? Эта escape-последовательность используется для завершения других escape-последовательностей, таких как \Q ... \E.   -  person TLP    schedule 26.02.2013
comment
Попробуйте это в целях отладки use Data::Dumper; $Data::Dumper::Useqq = 1; print Dumper \%tokendb, \%tokenfile;. Или, если это становится слишком запутанным, напечатайте значения в цикле: print Dumper "'$token' ne '$token2'"   -  person TLP    schedule 26.02.2013
comment
Предупреждение! Предупреждение! Если вы изучаете Perl из источника, который до сих пор называет хэши ассоциативными массивами, то вы изучаете из источника, который, вероятно, устарел более чем на пятнадцать лет.   -  person Dave Cross    schedule 27.02.2013


Ответы (2)


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

foreach $token (keys(%tokenfile)) {
  unless (exists $tokendb{$token}) {
    print "$token NOT IN DATABASE\n";
  }
}

вместо.

person Dave Sherohman    schedule 26.02.2013

foreach $token (keys(%tokenfile)) {
  if (! exists $tokendb{$token}) {
    print "$token NOT IN DATABASE\n";
  }
}

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

foreach $token (keys(%tokenfile)) {
  $found = 0;
  foreach $token2 (keys(%tokendb)) {
    if ($token eq $token2) {
      $found = 1;
      last;
    }
  }
  if (!found) {
    print "$token NOT IN DATABASE\n";
  }
}

Конечно, нет причин писать это таким образом, это просто поможет вам понять, почему ваша логика не удалась.

person Barmar    schedule 26.02.2013
comment
Вы, вероятно, должны указать, что цикл по хеш-ключам в этом случае излишен. Кроме того, я предполагаю, что вы имели в виду $found и last, а не found и break. - person TLP; 26.02.2013
comment
Спасибо, цените ваше время. Я думаю, мне следует больше читать об ассоциативных массивах, поскольку я думаю, что пытался не использовать exists и вместо этого использовал ne/eq. - person abstrakt; 27.02.2013