Как работает этот Perl grep для определения объединения нескольких хешей? - PullRequest
7 голосов
/ 15 апреля 2010

Я не понимаю последнюю строку этой функции из Программирование на Perl 3e .

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

@common = inter( \%foo, \%bar, \%joe );
sub inter {
    my %seen;
    for my $href (@_) {
        while (my $k = each %$href) {
            $seen{$k}++;
        }
    }
<strong>    return grep { $seen{$_} == @_ } keys %seen;</strong>
}

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

Ответы [ 3 ]

16 голосов
/ 15 апреля 2010

grep примет список, переданный ему (в этом случае каждый элемент, видимый в любом из хеш-ссылок); и возвращает список только тех элементов, для которых выражение в блоке имеет значение true (локально устанавливая переменную $_ для каждого элемента в списке).

Давайте посмотрим, как оценивается это выражение:

  • @_ - это массив всех параметров, переданных подпрограмме - в нашем случае это список хеш-ссылок, переданных в.

  • В $seen{$_} == @_ выражении этот список принудительно помещается в скалярный контекст (из-за ==).

  • При использовании в скалярном контексте список оценивается как количество элементов в списке - в приведенном выше примере вызов равен 3, поскольку в него передано 3 хеш-значения.

Итак, для каждого ключа в %seen (например, каждый ключ, видимый в любом из N хэш-ссылок); выражение $seen{$_} == @_ численно сравнивает число раз, которое элемент был замечен в хешах, с общим количеством хешей - конечно, оно будет равным, только если элемент находится во ВСЕХ хешах, которые были переданы, Таким образом, член пересечения мы хотим.

Итак, чтобы подвести итоги анализа, grep вернет список всех ключей , которые встречаются в КАЖДОМ хэше (то есть N раз, где N - количество хэшей) Например. пересечение.

3 голосов
/ 15 апреля 2010
grep block list 

Это будет применять блок к каждому элементу списка по очереди, элемент будет иметь псевдоним $ _. Если блок возвращает true, элемент добавляется в возвращаемый массив.

в этом случае:

grep { $seen{$_} == @_ } keys %seen

Блок равен $seen{$_} == @_, который сравнивает значение видимого хеша с @_. @_ вычисляется в скалярном контексте и, таким образом, возвращает количество элементов в массиве @_. @_ представляет аргументы текущей функции. В этом случае ( \%foo, \%bar, \%joe ), который возвращает 3 в скалярном контексте. Наш список keys %seen, который представляет собой массив, содержащий все ключи, присутствующие в %seen.

эквивалент английских утверждений:

  • "дайте мне список всех ключей от %seen где значение связано с этот ключ равен числу элементы, переданные этой функции "
  • "дайте мне список всех ключей от %seen где значение связано с этот ключ 3 "
  • "дай мне список все ключи от %seen, которые имеют значение 3, т.е. все ключи от %seen которые присутствуют в каждом из 3 хэш-функции переданы этой функции "
2 голосов
/ 15 апреля 2010

Цель функции - найти элементы, которые появляются во всех передаваемых ей хешах.

Последняя строка grep s списка, возвращенного с keys %seen. Чтобы определить, присутствует ли данный ключ во всех хешах, которые были переданы функции, мы можем сравнить значение этого ключа в %seen с количеством аргументов до inter.

В блоке grep $_ устанавливается для каждого элемента списка keys и проверяется на некоторые условия.

Массив в скалярном контексте оценивается по длине. @_ - массив аргументов, передаваемых в подпрограмму. А оператор == помещает свои операнды в скалярный контекст, поэтому мы можем просто сравнить значение $seen{$_} с длиной @_. Если они одинаковые, то этот ключ появился во всех хешах.

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