IT story

Perl 배열에 특정 값이 포함되어 있는지 어떻게 확인할 수 있습니까?

hot-time 2020. 4. 19. 13:57
반응형

Perl 배열에 특정 값이 포함되어 있는지 어떻게 확인할 수 있습니까?


배열을 반복하지 않고 배열에 값이 있는지 확인하는 방법을 찾으려고합니다.

매개 변수 파일을 읽고 있습니다. 처리하고 싶지 않은 매개 변수의 긴 목록이 있습니다. 이러한 원치 않는 매개 변수를 배열에 배치했습니다 @badparams.

새 매개 변수를 읽고 싶습니다.에없는 경우 @badparams처리하십시오. 에이 (가) 있으면 @badparams다음 읽기로 이동하십시오.


간단히 배열을 해시로 바꾸십시오.

my %params = map { $_ => 1 } @badparams;

if(exists($params{$someparam})) { ... }

목록에 더 많은 (고유 한) 매개 변수를 추가 할 수도 있습니다.

$params{$newparam} = 1;

나중에 (고유 한) 매개 변수 목록을 다시 가져옵니다.

@badparams = keys %params;

최상의 범용 – 특히 짧은 배열 (1000 개 이하) 및 요구 사항에 가장 적합한 최적화가 확실하지 않은 코더.

# $value can be any regex. be safe
if ( grep( /^$value$/, @array ) ) {
  print "found it";
}

grep은 배열의 첫 번째 값이 일치하더라도 모든 값을 통과한다고 언급했습니다. 이것은 사실이지만 grep은 여전히 ​​대부분의 경우 매우 빠릅니다 . 짧은 배열 (1000 개 미만의 항목)에 대해 말하면 대부분의 알고리즘은 어쨌든 매우 빠릅니다. 매우 긴 배열 (1,000,000 품목)에 대해 이야기하고 있다면 grep은 항목이 배열의 첫 번째인지 중간인지 마지막인지에 관계없이 매우 빠릅니다.

더 긴 어레이를위한 최적화 사례 :

배열이 정렬 된 경우 "이진 검색"을 사용하십시오.

은 IF 와 동일한 배열을 반복적으로 검색하여 여러 번, 제 해시에 복사 한 다음 해시를 확인한다. 메모리가 중요한 경우 각 항목을 배열에서 해시로 이동하십시오. 더 메모리 효율적이지만 원래 배열을 파괴합니다.

경우 같은 값이 반복적으로 검색되는 배열 내에서 유유히 캐시를 구축 할 수 있습니다. (각 항목을 검색 할 때 먼저 검색 결과가 지속 된 해시에 저장되어 있는지 확인하십시오. 검색 결과가 해시에서 발견되지 않으면 배열을 검색하고 결과를 지속 된 해시에 넣어 다음에 우리가 해시에서 찾은 다음 검색을 건너 뜁니다.

참고 : 이러한 최적화는 긴 배열을 처리 할 때만 더 빠릅니다. 과도하게 최적화하지 마십시오.


다음과 같이 Perl 5.10 에서 스마트 매치 기능을 사용할 수 있습니다 .

리터럴 값 조회의 경우 아래 작업을 수행하면 트릭이 수행됩니다.

if ( "value" ~~ @array ) 

스칼라 조회의 경우 아래 작업을 수행하면 위와 같이 작동합니다.

if ($val ~~ @array)

아래를 수행하는 인라인 배열의 경우 위와 같이 작동합니다.

if ( $var ~~ ['bar', 'value', 'foo'] ) 

에서 펄 5.18 그러므로 당신이 설정하여 경고를 해제해야 실험적으로 플래그가 smartmatch 실험 스크립트 / 모듈에 아래 추가하여 프라그 :

use experimental 'smartmatch';

또는 smartmatch의 사용을 피하려면 Aaron이 말한 것처럼 :

if ( grep( /^$value$/, @array ) ) {
  #TODO:
}

이 블로그 게시물 에서는이 질문에 대한 최상의 답변에 대해 설명합니다.

간단한 요약으로 CPAN 모듈을 설치할 수있는 경우 가장 읽기 쉬운 솔루션은 다음과 같습니다.

any(@ingredients) eq 'flour';

또는

@ingredients->contains('flour');

그러나 더 일반적인 관용구는 다음과 같습니다.

any { $_ eq 'flour' } @ingredients

그러나 first()기능을 사용하지 마십시오 ! 코드의 의도를 전혀 나타내지 않습니다. ~~"스마트 일치"연산자를 사용하지 마십시오. 작동하지 않습니다 . 그리고 grep()해시와 함께 솔루션을 사용 하거나 사용하지 마십시오 . 전체 목록을 반복합니다.

any() 값을 찾으면 바로 중지됩니다.

자세한 내용은 블로그 게시물을 확인하십시오.


사용하기 편리하지만 해시 변환 솔루션은 상당히 많은 비용이 들기 때문에 문제가되었습니다.

#!/usr/bin/perl
use Benchmark;
my @list;
for (1..10_000) {
    push @list, $_;
}

timethese(10000, {
  'grep'    => sub {
            if ( grep(/^5000$/o, @list) ) {
                # code
            }
        },
  'hash'    => sub {
            my %params = map { $_ => 1 } @list;
            if ( exists($params{5000}) ) {
                # code
            }
        },
});

벤치 마크 테스트 결과 :

Benchmark: timing 10000 iterations of grep, hash...
          grep:  8 wallclock secs ( 7.95 usr +  0.00 sys =  7.95 CPU) @ 1257.86/s (n=10000)
          hash: 50 wallclock secs (49.68 usr +  0.01 sys = 49.69 CPU) @ 201.25/s (n=10000)

@eakssjo의 벤치 마크 가 깨졌습니다. 루프에서 해시 생성과 루프에서 정규 표현식 생성 측정. 고정 버전 (및 추가 한 List::Util::firstList::MoreUtils::any) :

use List::Util qw(first);
use List::MoreUtils qw(any);
use Benchmark;

my @list = ( 1..10_000 );
my $hit = 5_000;
my $hit_regex = qr/^$hit$/; # precompute regex
my %params;
$params{$_} = 1 for @list;  # precompute hash
timethese(
    100_000, {
        'any' => sub {
            die unless ( any { $hit_regex } @list );
        },
        'first' => sub {
            die unless ( first { $hit_regex } @list );
        },
        'grep' => sub {
            die unless ( grep { $hit_regex } @list );
        },
        'hash' => sub {
            die unless ( $params{$hit} );
        },
    });

그리고 결과 (@eakssjo의 답변보다 10 배 더 많은 100_000 회 반복)입니다.

Benchmark: timing 100000 iterations of any, first, grep, hash...
       any:  0 wallclock secs ( 0.67 usr +  0.00 sys =  0.67 CPU) @ 149253.73/s (n=100000)
     first:  1 wallclock secs ( 0.63 usr +  0.01 sys =  0.64 CPU) @ 156250.00/s (n=100000)
      grep: 42 wallclock secs (41.95 usr +  0.08 sys = 42.03 CPU) @ 2379.25/s (n=100000)
      hash:  0 wallclock secs ( 0.01 usr +  0.00 sys =  0.01 CPU) @ 10000000.00/s (n=100000)
            (warning: too few iterations for a reliable count)

방법 1 : grep (값이 정규 표현식 인 경우주의 할 수 있음)

grep리소스 를 살펴보면를 사용하지 마십시오 .

if ( grep( /^$value$/, @badparams ) ) {
  print "found";
}

방법 2 : 선형 검색

for (@badparams) {
    if ($_ eq $value) {
       print "found";
    }
}

방법 3 : 해시 사용

my %hash = map {$_ => 1} @badparams;
print "found" if (exists $hash{$value});

방법 4 : 스마트 매치

(Perl 5.10에 추가 된 Mark는 Perl 5.18에서 실험적 임).

use experimental 'smartmatch';  # for perl 5.18
print "found" if ($value ~~ @badparams);

방법 5 : 코어 모듈 사용 List::MoreUtils

use List::MoreUtils qw(any uniq);;
@badparams = (1,2,3);
$value = 1;
print "found" if any {$_ eq $value} @badparams;

@files는 기존 배열입니다

my @new_values =  grep(/^2[\d].[\d][A-za-z]?/,@files);

print join("\n", @new_values);

print "\n";

/^2[\d].[\d][A-za-z]?/ = 2에서 시작하는 값은 정규식을 넣을 수 있습니다


당신은 확실히 해시를 원합니다. 잘못된 매개 변수를 해시의 키로 배치 한 다음 특정 매개 변수가 해시에 존재하는지 판별하십시오.

our %bad_params = map { $_ => 1 } qw(badparam1 badparam2 badparam3)

if ($bad_params{$new_param}) {
  print "That is a bad parameter\n";
}

배열을 사용하여 실제로 관심이 있다면 List::Util또는List::MoreUtils


이를 수행 할 수있는 두 가지 방법이 있습니다. 다른 게시물에서 제안한대로 조회 값을 조회 테이블의 해시에 던져 넣을 수 있습니다. (또 다른 관용구를 추가하겠습니다.)

my %bad_param_lookup;
@bad_param_lookup{ @bad_params } = ( 1 ) x @bad_params;

그러나 데이터가 대부분 단어 문자이고 메타가 너무 많지 않은 경우 정규식 대체로 덤프 할 수 있습니다.

use English qw<$LIST_SEPARATOR>;

my $regex_str = do { 
    local $LIST_SEPARATOR = '|';
    "(?:@bad_params)";
 };

 # $front_delim and $back_delim being any characters that come before and after. 
 my $regex = qr/$front_delim$regex_str$back_delim/;

이 솔루션은 원하는 "잘못된 값"유형에 맞게 조정해야합니다. 다시 말하지만, 특정 유형의 현에는 전혀 부적절 할 수 있으므로 주의하십시오 .


my @badparams = (1,2,5,7,'a','zzz');

my $badparams = join('|',@badparams);   # '|' or any other character not present in params

foreach my $par (4,5,6,7,'a','z','zzz')
{
    if ($badparams =~ /\b$par\b/)
    {
        print "$par is present\n";
    }
    else
    {
        print "$par is not present\n";
    }
}

숫자 선행 공백이 일치하는지 확인할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/2860226/how-can-i-check-if-a-perl-array-contains-a-particular-value

반응형