2016-12-11 4 views
4

나는 펄에서 다른 배열을 사용하는 용어의 배열을 필터링하기 위해 노력하고있어 크기를 조정. 필자는 Perl 5.18.2를 OS X에 가지고 있지만, 동작은 동일하다. (use 5.010).펄 : 배열 항목을 제거하고 배열

#!/usr/bin/perl 
#use strict; 
my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon', 
      'zeta','eta','theta chi','one iota','kappa'); 
my @filters = ('beta','gamma','epsilon','iota'); 
foreach $filter (@filters) { 
    for my $ind (0 .. $#terms) { 
     if (grep { /$filter/ } $terms[$ind]) { 
      splice @terms,$ind,1; 
     } 
    } 
} 

이것은 다양한 검색어와 일치하는 줄을 꺼내지 만 배열 길이는 변경되지 않습니다. 나는 결과 @terms 배열을 작성하는 경우, 내가 얻을 : 당신이 기대 한대로

[alpha] 
[delta quadrant] 
[zeta] 
[eta] 
[theta chi] 
[kappa] 
[] 
[] 
[] 
[] 

scalar(@terms)를 인쇄하는 10의 결과를 가져옵니다.

은 내가 원하는 말에 4 개 개의 빈 항목없이, 길이 6의 결과 배열입니다. 어떻게 결과를 얻을 수 있습니까? perldoc page about splice에 "어레이가 필요에 따라 커지거나 줄어드는"것을 감안할 때 왜 어레이가 축소되지 않는가?

(당신이 "그냥 ...?하지 않는 이유", 그것은 거의 확실입니다 그것에 대해 모르거나 이해하지 않았기 때문에 생각하고 있다면 펄에서 매우 유창하지, 그래서 당신은 항상 배열 마이너스 일을 다시 할 수있을 때 그것에 대해 들었습니다.)

+1

'grep' 배열과 요소를 일치 반환에 작동합니다. 아마 $ terms [$ ind] = ~/$ filter /'를 하나만 매치하는 것이 어떨까요? – tadman

+0

네, 고의로 고맙습니다! 배열이 왜 내가 전에하고 있던 일로 줄어들지 않았는지 아직도 혼란 스럽다. –

+0

적극적으로 반복하는 배열에서 요소를 제거하는 것은 항상 까다로운 작업입니다. 그것은 당신이 뭔가를 겹칠 때마다 오프셋을 1 씩 이동시킵니다. – tadman

답변

7

당신은 원하지 않는다. 당신은 어떤을 원하고 어떤 요소를 결정할 수 있도록 필터로 grep 행위는하지 않습니다 : 당신이 손에 %filter_exclusion처럼 간단한 구조를 가지고있는 경우

#!/usr/bin/perl 

use strict; 

my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon', 
      'zeta','eta','theta chi','one iota','kappa'); 
my @filters = ('beta','gamma','epsilon','iota'); 

my %filter_exclusion = map { $_ => 1 } @filters; 

my @filtered = grep { !$filter_exclusion{$_} } @terms; 

print join(',', @filtered) . "\n"; 

그것은 꽤 간단합니다.

업데이트은 : 허용 할 경우 임의의 문자열 일치 :

my $filter_exclusion = join '|', map quotemeta, @filters; 

my @filtered = grep { !/$filter_exclusion/ } @terms; 
+0

그것만이 부분적으로 작동합니다 - 그것은'gamma'와'epsilon'을 걸러 내고'beta test' 나'one isot'를 걸러냅니다. 미래의 프로젝트를 위해 유용 할 것입니다. –

+0

임의의 하위 문자열을 테스트하는 버전이 추가되었습니다. 이것은 정규 표현식을 다시 사용하지만 엔트리 당 하나의 테스트가 아니라 N 테스트를 사용합니다. – tadman

+0

쿨, 고마워! 그것은 실제로 효과가 있습니다. 당신이 생각하기에, 나는 그것이 어떻게 또는 왜 작동하는지 전혀 모른다. –

0

각 단계에서 배열의 내용을 인쇄, 무슨 일이 일어나고 있는지 확인하려면 : 당신이 배열을 스플 라이스 때, 축소,하지만 루프는 0 .. $ # terms을 반복하므로 루프의 끝에서 $ ind는 배열의 끝을 가리킬 것입니다. 당신이 grep { ... } $array[ $too_large ]을 사용하면 펄은 grep 블록 내부 $_에 존재하지 않는 요소의 별명을 할 필요가, 그래서 배열의 undef 요소를 만듭니다.

#!/usr/bin/perl 
use warnings; 
use strict; 
use feature qw{ say }; 

my @terms = ('alpha', 'beta test', 'gamma', 'delta quadrant', 'epsilon', 
      'zeta', 'eta', 'theta chi', 'one iota', 'kappa'); 
my @filters = qw(beta gamma epsilon iota); 

for my $filter (@filters) { 
    say $filter; 
    for my $ind (0 .. $#terms) { 
     if (grep { do { 
      no warnings 'uninitialized'; 
      /$filter/ 
     } } $terms[$ind] 
     ) { 
      splice @terms, $ind, 1; 
     } 
     say "\t$ind\t", join ' ', map $_ || '-', @terms; 
    } 
} 

당신이 $terms[$ind] =~ /$filter/ 대신 grep을 사용하는 경우에도 초기화되지 않은 경고를 얻을 싶지만, 요소의 별명을 할 필요가 없다, 그것은이 생성되지 않습니다.

+0

@ikegami : 출력에 '감마'가 표시되지 않습니다. 또한, 이것은 "수정"이 아니며, 후행 요소가 생성되는 이유를 설명해야합니다. 따라서 그들은 여전히 ​​거기에 있습니다. – choroba

+0

@ikegami : @terms "'를'인쇄 '하면'알파 델타 사분면 제타 에타 쎄타 치 카파'가 보입니다. – choroba

+0

오 죄송합니다. 버그는'@terms = qw (gamma gamma kappa);'로 시작하면 발생합니다. 두번째 감마는'$ terms [0]'으로 옮겨 지는데, 이것은 다시 방문하지 않습니다. – ikegami