LINUX.ORG.RU

Функция grep в Perl

 ,


0

1

Доброго времени суток!

Подскажите, пожалуйста.

Есть скрипт:

#!/usr/bin/perl

use warnings;
use strict;
use v5.10;

my @list_with_duplicates = qw( 1 2 3 4 5 5 5 5 5 5 5 5 10 10 11 12 );
my %uniq = ();
my @unique_elements = grep { !$uniq{$_}++ } @list_with_duplicates;
say 'say join ",", %uniq;';
say join ",", %uniq;
say 'say join ",", keys %uniq;';
say join ",", keys %uniq;
say 'say join ",", @unique_elements;';
say join ",", @unique_elements;

Он выводит значения, которые не являются дубликатами из списка.

По какому принципу здесь отрабатывает фильтр { !$uniq{$_}++ }?

В описании функции grep написано, что функция grep оценивает значение BLOCK или EXPR на предмет совпадения с каждым элементом списка LIST (устанавливая локально значение $_ поочередно равным каждому элементу) и возвращает список значений, составленный из этих элементов, которые удовлетворяют критерию совпадения.

Если я правильно понимаю, то в фильтре, сначала проверяется, есть ли в хэше %uniq ключ $_, если нет, то он записывается в хэш, далее переходим к следующему элементу $_ по списку. Если запись успешна, то он добавляется в @unique_elements. Так как ключ-значение в хэше - это уникальная пара элементов, мы не можем записать ключ в хэш, который и так там уже присутствует.

Не совсем понимаю, для чего используется !, чтобы отсеять дубликаты? При каком условии срабатывает переход к следующему элементу ++ или переход срабатывает для всего списка, независимо от того, выполнилось условие или нет? Откуда берутся значения values в хэше %uniq? Просто они не совпадают с входным списком.

Спасибо за внимание!

сначала проверяется, есть ли в хэше %uniq ключ $_, если нет, то он записывается в хэш

нэт. $uniq{$_}++ - просто считает кол-во $_ элементов. Ну и ! чтоб получить когда в uniq нет $_ (т.е. когда $uniq{$_} is undef) в результат грепа. Просто сделай say Dumper(\%uniq); и сам увидишь.

say Dumper(\%uniq);

$VAR1 = {
          '5' => 8,
          '1' => 1,
          '12' => 1,
          '4' => 1,
          '11' => 1,
          '3' => 1,
          '10' => 2,
          '2' => 1
        };

чтоб совсем стало понятно выполни

my ($t1, $t2, $t3) = (undef, 1, 2);
say Dumper(!$t1++);
say Dumper(!$t2++);
say Dumper(!$t3++);

vtVitus ★★★★★ ()
Последнее исправление: vtVitus (всего исправлений: 1)
my @unique_elements = grep { !$uniq{$_}++ } @list_with_duplicates;

grep возвращает элементы для которых верно условие, эквиватентный код

for(@list_with_duplicates){
  if(!$uniq{$_}){
    $uniq{$_}++;
    push @unique_elements, $_;
  }
}
pru-mike ★★ ()
Ответ на: комментарий от vtVitus

Получаю такой вывод:

$VAR1 = {
          '10' => 2,
          '2' => 1,
          '1' => 1,
          '4' => 1,
          '11' => 1,
          '3' => 1,
          '5' => 8,
          '12' => 1
        };

$VAR1 = 1;

$VAR1 = '';

$VAR1 = '';

Из undef -> 1

Из 1 -> пустота

Из 2 -> пустота

Видимо, потому что у нас нет следующего элемента $_?

Если с t2, t3, вроде бы, понятно, но откуда получаем из undef единицу, не совсем ясно.

По поводу say Dumper(\%uniq);, откуда берутся значения, к сожалению, не понял.

Спасибо за ответ.

ameame2021 ()
Ответ на: комментарий от ameame2021

откуда берутся значения, к сожалению, не понял

А ты подумай, напиши примитивные примеры аля

#!/usr/bin/perl -w

my ($t, $t1) = (undef, undef);

print $t++ . ", '" . !$t1++ . "'\n";
print $t++ . ", '" . !$t1++ . "'\n";
print $t++ . ", '" . !$t1++ . "'\n";
print $t++ . ", '" . !$t1++ . "'\n";
print $t++ . ", '" . !$t1++ . "'\n";
0, '1'
1, ''
2, ''
3, ''
4, ''
1 - это true, и значение попадает в выборку grep, пусто это false и значение в выборку не попадает.

эквиватентный код

нет представленный код не эквивалент кода из grep.

vtVitus ★★★★★ ()
Ответ на: комментарий от vtVitus

Действительно, тогда так

for(@list_with_duplicates){
  if(!$uniq{$_}){
    push @unique_elements, $_;
  }
  $uniq{$_}++;
}
pru-mike ★★ ()
Ответ на: комментарий от pinachet

Вот только мы имеем дело не с программой на Си. Поэтому:

  • надо загрузить дополнительный модуль
  • передать туда ввод
  • получить вывод
  • XS может поломать обратную совместимость
  • модуль может быть собран и без Си
level1 ()
Ограничение на отправку комментариев: только для зарегистрированных пользователей