programing

Perl 배열에 특정 값이 포함되어 있는지 확인하려면 어떻게 해야 합니까?

megabox 2023. 5. 29. 10:28
반응형

Perl 배열에 특정 값이 포함되어 있는지 확인하려면 어떻게 해야 합니까?

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

파라미터 파일을 읽고 있습니다.처리하고 싶지 않은 매개 변수 목록이 너무 많습니다.는 이 않는 .@badparams.

변수를 , 만약 에는 "" "" "" "" "" " " " " "에 있습니다.@badparams처리합니다.존재하는 경우@badparams다음 읽기로 이동합니다.

가장 일반적인 용도 - 특히 요구에 가장 적합한 최적화가 무엇인지 확실하지 않은 짧은 어레이(1000개 이하의 항목) 및 코더.

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

배열의 첫 번째 값이 일치하더라도 grep는 모든 값을 통과한다고 언급되었습니다.그러나 대부분의 경우 grep는 여전히 매우 빠릅니다.짧은 어레이(1000개 미만의 항목)를 말하는 경우 대부분의 알고리즘은 어쨌든 매우 빠릅니다.매우 긴 배열(1,000,000개의 항목)을 사용하는 경우, 항목이 배열의 첫 번째인지, 중간인지, 마지막인지에 관계없이 grep는 허용 가능한 빠른 속도입니다.

장기 어레이에 대한 최적화 사례:

배열이 정렬된 경우 "이진 검색"을 사용합니다.

동일한 배열을 여러반복 검색할 경우 먼저 해시에 복사한 다음 해시를 확인합니다.메모리에 문제가 있는 경우 어레이의 각 항목을 해시로 이동합니다.메모리 효율성은 향상되지만 원래 어레이는 파괴됩니다.

어레이 내에서 동일한 값이 반복적으로 검색되는 경우 캐시를 천천히 구축합니다.(각 항목을 검색할 때 먼저 검색 결과가 지속 해시에 저장되었는지 확인하고, 검색 결과가 해시에 없으면 배열을 검색한 다음 지속 해시에 결과를 저장하여 다음 번에는 해시에서 검색하고 검색을 건너뜁니다.)

참고: 이러한 최적화는 긴 어레이를 다룰 때만 더 빠릅니다.지나치게 최적화하지 마십시오.

어레이를 해시로 변환하기만 하면 됩니다.

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

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

목록에 추가(고유한) 파라미터를 추가할 수도 있습니다.

$params{$newparam} = 1;

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

@badparams = keys %params;

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

문자 그대로의 값 조회에 대해서는 아래와 같이 하면 됩니다.

if ( "value" ~~ @array ) 

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

if ($val ~~ @array)

아래에서 수행하는 인라인 어레이의 경우 위와 같이 작동합니다.

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

Perl 5.18에서는 smartmatch가 experimental로 플래그가 지정되므로 스크립트/모듈에 아래를 추가하여 experimental pragma를 설정하여 경고를 해제해야 합니다.

use experimental 'smartmatch';

또는 Aaron이 말한 것처럼 스마트 매치를 사용하지 않으려면 다음을 사용합니다.

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

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

요약하자면 CPAN 모듈을 설치할 수 있는 경우 가장 읽기 쉬운 솔루션은 다음과 같습니다.

any(@ingredients) eq 'flour';

또는

@ingredients->contains('flour');

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

any { $_ eq 'flour' } @ingredients

하지만 사용하지 마십시오.first()함수! 코드의 의도를 전혀 표현하지 않습니다.~~ 매치".스마트 매치" 연산자: 고장났습니다.사용안을 .grep()해시가 있는 솔루션도 아닙니다. 전체 목록을 반복합니다.

any()값을 찾는 즉시 중지됩니다.

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

방법 1: grep(값이 정규식이 될 것으로 예상되는 동안 주의할 수 있음).

사용하지 않도록 하십시오.grep자원을 살펴보면요.

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

방법 2: 선형 검색

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

방법 3: 해시 사용

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

방법 4: 스마트 매치

(Perl 5.10에서 추가되었으며 Perl 5.18에서는 실험 버전으로 표시됨).

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

5:합니다.List::MoreUtils

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

@eakssjo의 벤치마크가 깨졌습니다. 루프에서 해시를 생성하는 것과 루프에서 정규식을 생성하는 것을 비교합니다.고정 버전(게다가 추가했습니다)List::Util::first그리고.List::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} );
        },
    });

그 결과(100_000번 반복되는 것으로, @eakssjo의 답변보다 10배 더 많습니다):

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)

사용이 편리함에도 불구하고, Convert-to-Hash 솔루션은 성능비가 많이 드는 것 같아 저는 고민했습니다.

#!/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)

@파일이 기존 어레이임

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부터 시작하는 vaues 여기에 임의의 정규식을 넣을 수 있습니다.

당신은 확실히 여기서 해시를 원합니다.잘못된 매개 변수를 해시에 키로 배치한 다음 특정 매개 변수가 해시에 있는지 여부를 결정합니다.

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

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

것에 , ,▁at▁if▁look,List::Util또는List::MoreUtils

배열에 있는 모든 요소의 양을 알아야 할 경우 해당 요소의 존재 외에 사용할 수 있습니다.

my %bad_param_lookup;
@bad_param_lookup{ @bad_params } = ( 1 ) x @bad_params;
%bad_param_lookup = map { $_ => $bad_param_lookup{$_}++} @bad_params;

그런 다음 @bad_params에 있는 모든 $i에 대해 $bad_param_params{$i}에는 @bad_params에 있는 $i의 양이 포함됩니다.

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

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

반응형