2010-10-18 4 views
24

Здесь я пытаюсь отфильтровать только те элементы, у которых нет подстроки world, и сохранить результаты обратно в тот же массив. Каков правильный способ сделать это в Perl?Как фильтровать массив без использования цикла в Perl?

$ cat test.pl 
use strict; 
use warnings; 

my @arr = ('hello 1', 'hello 2', 'hello 3', 'world1', 'hello 4', 'world2'); 

print "@arr\n"; 
@arr =~ v/world/; 
print "@arr\n"; 

$ perl test.pl 
Applying pattern match (m//) to @array will act on scalar(@array) at 
test.pl line 7. 
Applying pattern match (m//) to @array will act on scalar(@array) at 
test.pl line 7. 
syntax error at test.pl line 7, near "/;" 
Execution of test.pl aborted due to compilation errors. 
$ 

Я хочу передать массив в качестве аргумента подпрограмме.

Я знаю, что один из способов будет что-то вроде этого

$ cat test.pl 
use strict; 
use warnings; 

my @arr = ('hello 1', 'hello 2', 'hello 3', 'world1', 'hello 4', 'world2'); 
my @arrf; 

print "@arr\n"; 

foreach(@arr) { 
    unless ($_ =~ /world/i) { 
     push (@arrf, $_); 
    } 
} 
print "@arrf\n"; 

$ perl test.pl 
hello 1 hello 2 hello 3 world1 hello 4 world2 
hello 1 hello 2 hello 3 hello 4 
$ 

Я хочу знать, если есть способ сделать это без цикла (с помощью простой фильтрации).

ответ

31

Это было бы grep():

#!/usr/bin/perl 

use strict; 
use warnings; 

my @arr = ('hello 1', 'hello 2', 'hello 3', 'world1', 'hello 4', 'world2'); 
my @narr = (); 

print "@arr\n"; 
@narr = grep(!/world/, @arr); 
print "@narr\n"; 
8

Использование grep

@no_world_for_tomorrow = grep { !/world/ } @feathers; 

Для получения дополнительной информации, perldoc -f grep.

4

Вы можете использовать функцию grep как:

@arrf = grep(!/world/, @arr); 

Выражение !/world/ вычисляется для каждого элемента массива @arr и список элементов, который возвращается выражение оценивается, чтобы быть правдой.

Выражение /world/ ищет слово world и является ли оно истинным. И выражение !/world/ истинно, если строка world отсутствует.

11

Использование grep:

sub remove_worlds { grep !/world/, @_ } 

Например:

@arrf = remove_worlds @arr; 

Использование grep является наиболее естественным для вашей конкретной проблемы, но для полноту, вы также можете сделать это с помощью map:

sub remove_worlds { map /world/ ?() : $_, @_ } 

Это немного klunky здесь, но map дает крюк в случае, если вы хотите обработать отфильтрованные элементы, прежде чем выбросить их.

+0

Хорошо, что ссылки для ссылок здесь. – Wolf

+0

Синтаксис '!/Match /' отрицательного соответствия был критическим. Я рассматривал карту и другие решения, но все они казались слишком неуклюжими для perl. – davenpcj

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