2016-07-29 10 views
2

私はオンラインで見て、誰もが同じ意味で使われていると言います。しかし、それは私の配列を反復処理していたときに私に異なる結果をもたらしました。Perl:forとforeachはなぜ私に異なる結果を与えるのですか?

私は、 60個の文字列要素を持ち、別の配列で一致するものを除外していました。しかし、私がforeachを使用したとき、それは45要素の配列しか見なかったので、最終結果を印刷したときにすべてをフィルタリングしませんでした。

forを使用したときだけ、私が望むように動作しました。これの背後にある理由は何ですか?

私はこの問題を解決することができましたが、今はその仕組みを理解したいだけです。ありがとう!

EDIT:だから私はここに例を提供していなかった私がやったことだ:

my $i = 0; 
foreach my $item (@array){ 
    print "\n$i : $item"; 
    foreach my $exclude_item (@exclude){ 
     chomp $exclude_item; 
     if ($exclude_item eq $item){ 
      print "\nDEBUG: Removing $item"; 
      splice @array, $i, 1; 
     } 
    } 
    $i++; 
} 

上記は私に@arrayの完全なリストを与えていなかったので、私は最終的な結果を印刷したときに、要素がありました内部は除外されているはずです。

は、だから私は(私が望んでいたとして働いていた)の代わりにこれを試してみました:

for (my $i=0; $i < scalar @array; $i++){ 
    print "\n$i : $array[$i]"; 
    foreach my $exclude_item (@exclude){ 
     chomp $exclude_item; 
     if ($exclude_item eq $array[$i]){ 
      print "\nDEBUG: Removing $array[$i]"; 
      splice @array, $i, 1; 
     } 
    } 
} 

ただ、追加情報、@arrayは、複数のフォルダにサブディレクトリのリストを検索することによって作成されました。 @arrayに重複が含まれている可能性があります。

+9

他の何かが異なっていました。 'for 'と' foreach'はレクサーと完全に区別できません。彼らはまったく同じものの2つの名前です。 – hobbs

答えて

14
# Foreach loop        \   
foreach my $item (@array)      > same  \ 
for my $item (@array)      /   \ 
                  > different 
# Augmented while loop      \   /
for (my $i=0; $i < scalar @array; $i++)  > same /
foreach (my $i=0; $i < scalar @array; $i++)/

あなたが反復その上に配列を変更してはなりません。 perlsynから、

LISTのいずれかの部分が配列である場合は、spliceと、たとえば、ループ本体内の要素を追加または削除する場合は、foreachは非常に混乱してしまいます。そうしないでください。あなたは安全にあなたが反復された上で、配列の要素を変更することがあり

したがって、

foreach (@array){ 
    ... 
    splice @array, $i, 1; # XXX Error 
    ... 
} 

注意。

foreach (@array){ 
    $_ = uc($_); # ok 
} 

最後に、はるかに良い解決策:

chomp(@exclude); 

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

@array = grep { !$exclude{$_} } @array; 

脇はるかに簡単であることから、それははるかに優れたスケール[1]


  1. これはOPの実行O中(E * )時間に対し、O(E + A)の時間で実行されます。人々は、彼らが交換可能に使用されていると言うとき
+1

私は真剣にあなたが私を感じるようにどのように愚かなことを憎む/愛している..それを言って、説明のおかげで言って!私はすべてのatmであなたの解決策を理解していないので、私はこれに私の金曜日の夜を過ごす必要があります。 –

+0

'my%exclude = map {$ _ => 1} @exclude;'はルックアップテーブルを作成するので、文字列を除外すべきかどうかを効率的に調べることができます。 '@array = grep {!$ exclude {$ _}} @array;'はルックアップテーブルにあるものを除いて '@ array'のすべての要素を保持します。 – ikegami

+0

完全性のために、ハッシュスライスメソッド 'my%exclude; @exclude {@exclude} =(1)x @ exclude'はもう一度速くなります。あなたは一度それを行う場合、それは2行の価値がないかもしれません。 – mbethke

6

は、彼らがforeachキーワードがちょうどforキーワードの同義語であることを意味します。私はforeachキーワードを無視して、以下のみforを使用します誤解を避けるために

foreach my $item (@array) {...} 
for my $item (@array) {...} 

:それは次の2行がまったく同じことを意味を意味します。

次の2行は、あなたが見てきたように、同じように動作しません:

for my $item (@array) {...} 
for (my $i = 0; $i < scalar @array; $i++) {...} 

manualは、最初の行のループ本体に@array内の要素を追加または削除に対するアドバイス、そして言っていません何が結果になるでしょうか。

$iまたはそれ以前に@arrayの要素を2行目のループ本体で削除すると、新しい位置$iの要素がスキップされます。 $iの前またはそれ以前に要素を追加すると、その結果、古い位置の要素$iがループによって2度目に表示されます。

関連する問題