2009-06-16 1 views
42

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

Вот что я делаю:

foreach $line (@lines){ 
    if(($line =~ m|my regex|)) 
    { 
     $string = $1; 
     if ($string is not a key in %strings) # "strings" is an associative array 
     { 
      $strings{$string} = 1; 
     } 
     else 
     { 
      $n = ($strings{$string}); 
      $strings{$string} = $n +1; 
     } 
    } 
} 
+4

Вопрос в том, почему вы даже беспокоитесь об этом? Если он не существует, то $ n будет undef. Числовое значение Undef равно 0, поэтому $ n + 1 = 1. Нет необходимости проверять, существует ли он в хеше. –

ответ

95

Я считаю, чтобы проверить, если ключ существует в хэш вы просто делаете

if (exists $strings{$string}) { 
    ... 
} else { 
    ... 
} 
+13

Имейте в виду, что perl будет автоматически генерировать любые промежуточные ключи, которые не существуют в многомерном хэше, чтобы «проверить», если существует ключ, который вы ищете в последнем хеше. Это не проблема с простым хэшем, как этот пример, но .. my% test =(); print "bar" if (существует $ test {'foo'} {'bar'}); # perl просто автогенерировал ключ foo, чтобы искать бар print "foo существует сейчас, и вы, возможно, не ожидали этого!" if (существует $ test {'foo'}); – Drew

6

Я думаю, что этот код должен ответить на ваш вопрос:

use strict; 
use warnings; 

my @keys = qw/one two three two/; 
my %hash; 
for my $key (@keys) 
{ 
    $hash{$key}++; 
} 

for my $key (keys %hash) 
{ 
    print "$key: ", $hash{$key}, "\n"; 
} 

Выход:

three: 1 
one: 1 
two: 2 

Итерация может быть упрощена:

$hash{$_}++ for (@keys); 

(см $_ в perlvar.) И вы можете даже написать что-то вроде этого:

$hash{$_}++ or print "Found new value: $_.\n" for (@keys); 

Какие отчеты каждый ключ в первый раз это найденный.

+0

Да, дело в том, что я не буду знать заранее, какие ключи будут. –

+1

Да, вам не нужно проверять наличие ключа для этой цели. Вы можете просто сказать $ strings {$ 1} ++. Если ключ отсутствует, он будет добавлен с undef как значение, которое ++ будет интерпретировать как 0 для вас. – Arkadiy

+0

Несомненно. Дело в том, что вы можете заменить весь тело вашего цикла (под if) на $ strings {$ 1} ++. – zoul

-1

Вы можете просто пойти с:

if(!$strings{$string}) .... 
+0

Да, это тоже работает. Благодаря! –

+7

Это работает только в том случае, если все ключи имеют значения, которые не являются ложными. В общем, это плохое предположение. Используйте exists(), который специально разработан именно для этого. –

+2

@brian de foy - Ах, ха. Я знал, что не должен был отвечать :-) –

9

Ну, весь ваш код может быть ограничен:

foreach $line (@lines){ 
     $strings{$1}++ if $line =~ m|my regex|; 
} 

Если значение не существует, ++ оператор будет считать его равным 0 (а затем увеличивайте до 1). Если он уже существует, он просто будет увеличен.

+0

Хотя ваш ответ верен, он отвечает на вопрос о хешах. – Chris

9

Я бы советовал не использовать if ($hash{$key}), поскольку он не будет делать то, что вы ожидаете, если ключ существует, но его значение равно нулю или пусто.

+1

Эти определенные обстоятельства предназначены только для вложенных ключей. Для этой проблемы существует ответ. Не использовать существует для вложенных ключей одним выстрелом. –

+1

Downvote все еще немного суровый, хотя - предупреждение не отменено простотой скрипта в этом вопросе. Более важным моментом является вопрос об использовании if ($ hash {$ key}), который не определен и не существует: проблема «ноль, но истинная». – RET

+0

«Нулевая, но истинная» вещь заслуживает повышения. Но то, что вы сказали об автовивитации, просто неверно и заслуживает понижения. – innaM

Смежные вопросы