Пытаясь понять этот Perl-скрипт - PullRequest
3 голосов
/ 08 августа 2011

Это кажется очень простым, и я понял большую часть этого. Но, учитывая, что Perl плохо работает с синтаксисом, новичку трудно прыгнуть прямо в:)

my @unique = ();
my %seen   = ();
foreach my $elem ( @array ) {
    next if $seen{ $elem }++;
    push @unique, $elem;
}

Это прямо с сайта perldoc. Если я правильно понимаю, это также можно записать как:

my @unique = ();
my %seen   = ();
my $elem;
foreach $elem ( @array ) {
    if ( $seen{ $elem }++ ) {
        next;
    }
    push ( @unique, $elem );
}

Итак, мое понимание на данный момент:

  • Объявить массив с именем уникальным
  • Объявить хеш с именем увиденного
  • Объявить переменную с именем elem
  • Итерация по @array, каждая итерация сохраняется в $ elem
  • Если $ elem является ключом в увиденном хеш-% (я понятия не имею, что делает ++), перейдите к следующей итерации
  • Добавить $ elem в конец @ unique

Мне не хватает 2 вещей:

  • Когда что-либо сохраняется в% увиденного?
  • Что делает ++ (на любом другом языке он увеличивается, но я не понимаю, как это работает)

Я знаю, что проблема заключается в этой части:

$seen{ $elem }++

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

Спасибо за помощь

Ответы [ 4 ]

4 голосов
/ 08 августа 2011

Оператор ++ делает практически то же самое в Perl, как и в большинстве других языков, где он есть: он увеличивает переменную.

$seen{ $elem }++;

увеличивает значение в %seen, а именно то, чей ключ равен $elem.

"Волшебство" заключается в том, что если $seen{$elem} еще не определено, оно создается автоматически, как если бы оно уже существовало и имело значение 0; ++ затем устанавливает его на 1. Так что это эквивалентно:

if (! exists $seen{$elem}) {
    $seen{$elem} = 0;
}
$seen{$elem} ++;

Это называется "автовивификацией". (Нет, действительно, это то, что он называется.) (EDIT2: Нет, моя ошибка, это не так; как указывает @ysth, термин «автовификация» на самом деле относится к ссылкам , возникающим в результате. См. perldoc perlref. )

РЕДАКТИРОВАТЬ: Вот пересмотренная версия вашего описания:

  • Объявите переменную массива с именем @ unique
  • Объявить хеш-переменную с именем% visible
  • Объявите скалярную переменную с именем $ elem
  • Итерация по @array, каждая итерация сохраняется в $ elem
  • Если $ elem является ключом в увиденном хеш-%, перейдите к следующей итерации
  • Добавить значение $ elem до конца @ unique

@unique, %seen и $elem являются переменными. Знак пунктуации (известный как «сигил») указывает, какую переменную каждый из них представляет, и о которой лучше всего думать как о части имени.

3 голосов
/ 08 августа 2011

Это общий шаблон в Perl для создания массива, состоящего из «уникальных» элементов в данном массиве.

В Perl хеш хранит значение, связанное с любым заданным ключом. Если вы ничего не поместили в хеш для данного ключа, вы получите undef - но в числовом контексте, например, когда вы выполняете операцию увеличения, undef обрабатывается как 0 а затем увеличивается.

Оператор if проверяет истинные или ложные значения, как вы знаете. В Perl 0, "0", '' (пустая строка) и undef (и, возможно, другие?) Рассматриваются как ложные значения.

Постинкремент, как и в C / C ++ / Java, возвращает исходное значение содержащемуся выражению. Итак, этот код

if ( $seen{ $elem }++ ) {
        next;
    }

вернет false (0) для элемента, который еще не был просмотрен, и цикл продолжится (то есть оператор next не будет выполняться). Элемент будет помещен в массив. Однако, прежде чем это произойдет, приращение происходит - теперь внезапно 1 сохраняется в хэше, что означает, что значение было просмотрено один раз. В следующий раз, когда это значение будет замечено, цикл будет пропущен, и значение больше не будет добавлено в массив результатов.

3 голосов
/ 08 августа 2011

Когда что-либо сохраняется в% увиденного?

Когда оно пытается увеличить его.

Что делает ++ (на любом другом языке)оно увеличивается, но я не понимаю, как это работает)

Увеличение неопределенной переменной делает ее 1

Это так же, как это:

my @unique = ();
my %seen   = ();
my $elem;
foreach $elem ( @array ) {
    if ( ! $seen{ $elem } ) {
         $seen{ $elem } = 1;  
    } else {
        $seen{ $elem }++;
        push ( @unique, $elem );
    }
}
1 голос
/ 08 августа 2011

Если в% нет элемента с ключом $ elem, то в этой строке будет создан новый элемент (новая запись в хеш-таблице) с ключом $ elem.++ после него является оператором приращения.Он добавляет единицу к значению $ seen {$ elem}.Поскольку начальное значение $ seen {$ elem} оценивается как ложное или ноль в числовом контексте, это увеличивает значение $ seen {elem} на единицу.Поскольку ++ находится справа от $ seen {$ elem}, он добавляется только после вычисления $ seen {elem}.Таким образом, при первом обнаружении какого-либо конкретного $ elem этот тест не пройден, и он перейдет к следующему шагу, добавив $ elem в список (массив) уникальных элементов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...