12

配列をループしていますが、要素が別の配列にあるかどうかをテストしたいと考えています。

疑似コードでは、私がやろうとしていることは次のとおりです。

foreach $term (@array1) {
    if ($term is found in @array2) { 
        #do something here
    }
}

私は「foreach」と「ここで何かをする」部分を軽視しています...しかし、「配列に用語が見つかった場合」テストのために試したものはすべて機能しません...

私はgrepを試しました:

if grep {/$term/} @array2 { #do something }
# this test always succeeds for values of $term that ARE NOT in @array2

if (grep(/$term/, @array2)) { #do something }
# this test likewise succeeds for values NOT IN the array

以前の多くの投稿で非常にシンプルで簡単であることが示されている「配列をハッシュに変換する」方法をいくつか試しましたが、どれもうまくいきませんでした。

私は perl の長年の低レベル ユーザーです。perl の基本しか理解していませんが、interweb で読んだソリューションの 99% を構成する複雑な難読化されたコードをすべて理解しているわけではありません。コードで明示されている回答を正直に評価し、コードが何をしているかの段階的な説明を提供してください...

... 私は真剣に $_ やその他の種類やタイプの隠された、理解された、または暗黙の値、変数、または関数を理解していません。例やサンプルにすべての変数と関数が明確な用語 ($_ ではなく $term) で名前が付けられていて、コードが何をしているのかをコメントで説明してくれると本当にありがたいです。いつかそれを理解することを望むかもしれません。お願いします。:-)

...

「grep」をある程度うまく使用する既存のスクリプトがあります。

$rc=grep(/$term/, @array);
if ($rc eq 0) { #something happens here }

しかし、まったく同じコードを新しいスクリプトに適用しましたが、正しく成功しません...つまり、配列に存在しないことがわかっている$termの値をテストすると、「成功」(rc =ゼロ)します。テスト済み。私はそれを理解していません。

「古い」スクリプトと「新しい」スクリプトの「grep」アプローチの唯一の違いは、配列の作成方法です...古いスクリプトでは、ファイルから読み取って配列を作成しました。

  @array=`cat file`;

一方、新しいスクリプトでは、配列をスクリプト自体の中に入れます(小さいので)...次のように:

  @array=("element1","element2","element3","element4");

その結果、grep 関数の出力がどのように異なるのでしょうか? それらは両方ともボグ標準の配列です! 理解できません!!!!:-(

#################################################### ######################

補遺...私の実際のコードのいくつかの説明または例:

#################################################### ######################

一致/検索/grepしようとしている用語は、「word123」などの単語要素です。

この演習は、がらくたでいっぱいのファイルから重要な情報を見つけるための簡単で汚いスクリプトであることを意図していたので、すべての細かな点 (厳密、警告、モジュール、サブルーチンを使用) を選択してスキップします...これはしません。シンプルである必要があります。

私が探している用語は、分割によってインスタンス化される変数に格納されます。

foreach $line(@array1) {
  chomp($line);  # habit

  # every line has multiple elements that I want to capture
  ($term1,$term2,$term3,$term4)=split(/\t/,$line);  

  # if a particular one of those terms is found in my other array 'array2'
  if (grep(/$term2/, @array2) { 
    # then I'm storing a different element from the line into a 3rd array which eventually will be outputted
    push(@known, $term1) unless $seen{$term1}++;
  }
}

そこにgrepがあるのがわかりますか?正しく動作しません...間違いなくarray2にない場合でも、$term2のすべての値に対して成功しています...array1は数千行のファイルです。ここで $term2 と呼んでいる要素は、複数の行にまたがる個別の用語ですが、特定の行内で繰り返されることはありません (またはより大きな文字列の一部)。Array2 は、出力のために「フィルター処理」する必要がある約数十の要素です。

...

以下の提案のいずれかを試しました。

if (grep $_ eq $term2, @array2) 

そして、この grep は $term2 のすべての値で失敗しました... grep からオール オア ナッシングの応答が返ってきました...だから、grep の使用をやめる必要があると思います。これらのハッシュ ソリューションの 1 つを試してみてください。

4

8 に答える 8

9

これはperlfaqにあります。手っ取り早い方法は、

my %seen;
$seen{$_}++ for @array1;
for my $item (@array2) {
    if ($seen{$item}) {
        # item is in array2, do something
    }
}

大文字と小文字が重要でない場合は、 でキーを設定し、$seen{ lc($_) }で確認できますif ($seen{ lc($item) })

到着予定時刻:

変更された質問: タスクが の 1 つの単語と@array2の行全体を照合することである場合、@array1タスクはより複雑になります。行を分割してハッシュキーと照合しようとすると、句読点やその他の理由で安全ではない可能性があります。したがって、正規表現ソリューションがおそらく最も安全です。

@array2非常に大きくない限り、次のようにすることができます。

my $rx = join "|", @array2;
for my $line (@array1) {
    if ($line =~ /\b$rx\b/) {  # use word boundary to avoid partial matches
        # do something
    }
}

@array2などのメタ文字が含まれている場合*?+|は、それらがエスケープされていることを確認する必要があります。その場合、次のようにします。

my $rx = join "|", map quotemeta, @array2;
# etc
于 2012-07-06T15:47:25.360 に答える
6

5.10 以降を使用している場合は、(悪名高い)「スマート マッチ」演算子を使用できます。

#!/usr/bin/perl
use strict;
use warnings;

my @array1 = qw/a b c d e f g h/; 
my @array2 = qw/a c e g z/; 

print "a in \@array1\n" if 'a' ~~ @array1;
print "z in \@array1\n" if 'z' ~~ @array1;
print "z in \@array2\n" if 'z' ~~ @array2;

この例は非常に単純ですが、必要に応じて RE を使用することもできます。いくつかのあいまいさと、ええと、「文書化されていない機能」があるため、誰もが ~~ を好むわけではないことを付け加えておきます。ただし、これで問題ないはずです。

于 2012-07-06T15:46:41.617 に答える
5

これは機能するはずです。

#!/usr/bin/perl
use strict;
use warnings;

my @array1 = qw/a b c d e f g h/;
my @array2 = qw/a c e g z/;

for my $term (@array1) {
    if (grep $_ eq $term, @array2) {
        print "$term found.\n";
    }
}

出力:

a found.
c found.
e found.
g found.
于 2012-07-06T15:37:03.657 に答える
2
#!/usr/bin/perl

@ar = ( '1','2','3','4','5','6','10' );
@arr = ( '1','2','3','4','5','6','7','8','9' ) ;

foreach $var ( @arr ){
    print "$var not found\n " if ( ! ( grep /$var/, @ar )) ;
}
于 2014-02-11T09:21:21.353 に答える
0

あなたの「実際のコード」はコンパイルさえすべきではありません:

if (grep(/$term2/, @array2) { 

次のようにする必要があります。

if (grep (/$term2/, @array2)) { 

コード内の括弧のバランスが取れていません。引数 (配列) で動作するコールバック (コード リファレンス) で grep を使用する方が簡単な場合もあります。これは、括弧がぼやけてしまうのを防ぐのに役立ちます。ただし、これはオプションです。それはそのようになります:

if (grep {/$term2/} @array2) { 

strict を使用することもできます。警告を使用します。このような問題をキャッチします。

于 2012-07-06T18:45:06.170 に答える