5

ここで同様のトピックが取り上げられていることは知っていますが、foreach ループのコンテキストで配列スライスがどのように補間されるかについての私の誤解から生じると思われる問題に直面しています。どこが間違っているのかわからないので、洞察を探しています。

行数が可変の 2D 配列があります。例として:

@2DArray = (['str1', 1, 2, 'E', val1, val2, val3]
            ['str2', 3, 4, 'E', val4, val5, val6]
            ['str4', 5, 6, 'F', val7, val8, val9])   

列 3 に文字列 'E' が含まれている場合にのみ、元の配列の行の一部を組み込む列を追加して、新しい配列を作成したいと考えています。さらに、新しい配列に組み込みたい行については、列のサブセットのみが必要で、そのサブセットを別の順序で並べたい。最終的な目標は、下流のスクリプトが必要とする正しい形式の出力を生成することです。

これが私の試みです:

my $projName = 'test';

my $i = 1;
my @Newarray
my @Newarray_element;
     foreach (@2DArray) {
         if  (${$_}[3] eq 'E') {
             ${$_}[3] = $i; 
             ${$_}[5] = '+'; 
             @Newarray_element = ("$projName$i", @$_[0,1,2,5,3], 'STR', 11, 11);
             $i++;
             push (@Newarray, \@Newarray_element);
         }

         next;
     }

print (join("\t", @$_), "\n") for @Newarray;

ただし、それを行うと、次のようになります。

#(original) col nums:      0       1    2    5    3

                  test2    str2    3    4    +    2    STR    11    11
                  test2    str2    3    4    +    2    STR    11    11

つまり、私の新しい配列には、列 3 に「E」がある元の配列のすべての行の行がありますが、各行には、ループによって処理される最後の行の値が入力されます。

問題が foreach ループで 2D 配列をスライスすることに関係していると思う理由は、単に 2D 配列をループして、列 3 に「E」があるすべての行を見つけ、他の列のいくつかの値を変更するかどうかを知っているからです。それらの行について、それを新しい配列に返すと、すべて完全に機能します。つまり、代わりにこれを行うと:

my @Newarray;
my $i = 1;
foreach (@2Darray) {
    if  (${$_}[3] eq "E") {
        ${$_}[3] = $i;
        ${$_}[5] = '+';
        $i++;
        push (@Newarray, \@$_);
    }
    next;   
}
print (join("\t", @$_), "\n") for @Newarray;

期待どおりの出力が得られます。

                  *            &
str1    1    2    1    val1    +    val3
str2    3    4    2    val4    +    val6

ここで、* と & でマークされた列は、変更された列 3 と 5 です。

4

1 に答える 1

4

変数@Newarray_elementはプログラム全体で同じメモリ空間を指しているため、1 回の反復で行った変更は、代入でその変数を使用した以前の反復に伝播されます。

2 つの可能な修正:

1 つ。変数のスコープを変更して、反復ごとに異なるメモリを使用するようにします。変化する

my @Newarray_element;
foreach (@2DArray) {
    ...

foreach (@2DArray) {
    my @Newarray_element;
    ...

あるいは

foreach (@2DArray) {
    ...
    my @Newarray_element = ("$projName$i", @$_[0,1,2,5,3], 'STR', 11, 11);

2 : 再利用しますが、そのデータのコピーを の各行に@Newarray_element割り当てます。変化する@Newarray

push (@Newarray, \@Newarray_element);

push (@Newarray, [ @Newarray_element ]);

この後者の呼び出しは、 への新しい無名配列参照を作成して追加し@Newarrayます。

于 2013-04-18T22:43:33.130 に答える