0

目標: 配列から特定の値を削除します

スクリプトを書きましたが、問題なく動作しますが、自分の書き方には満足できません。だから私はそれを書くためのより良い方法があることを知りたいと思っています. 以下の使用例を検討してください。

以下のように、ネストされたハッシュ/ハッシュ/配列があります。local名前に含まれる配列値を削除する必要があります。

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my $hash = { esx1 => 
                    { cluster   => "clu1",
                      fd        => "fd1",
                      ds        => [ 
                                        'ds1',
                                        'ds2',
                                        'localds',
                                    ],  
                    },  
            esx2 => 
                    { cluster   => "clu2",
                      fd        => "fd2",
                      ds        => [ 
                                        'ds3',
                                        'ds4',
                                        'dslocal',
                                    ],  
                    },  
            };  


foreach my $a ( keys %$hash )
{
    foreach ( 0..$#{ $hash->{$a}->{ds} } ) 
    {   
        delete $hash->{$a}->{ds}->[$_] if $hash->{$a}->{ds}->[$_] =~ /local/i;
        @{ $hash->{$a}->{ds} } = grep defined, @{ $hash->{$a}->{ds} };
    }   
}

print Dumper ($hash);

そのため、スクリプトは " localds" と " dslocal" を削除し、他のすべてをそのまま保持します。

質問:

  1. foreach ( 0..$#{$hash->{$a}->{ds} } )ループを書くためのよりクリーンな方法はありますか
  2. 上記の行を記述しない場合grep、結果の配列にはlocal削除された値が含まれますが、に置き換えられundefます。なぜこうなった。

ありがとう。

4

5 に答える 5

5

deleteハッシュの要素用です。実装の癖によってたまたま配列で動作しますが、依存するべきではありません。

配列の場合は、スプライスを使用します。

splice @{ $ref->{to}->{array} }, $index, 1, ();

これは、で始まる 1 要素のサブリストを空のリストである に置き換え$indexます()

于 2012-10-31T15:06:41.747 に答える
2

最初に配列を繰り返して要素を削除し、次に「削除されていない」ノードを探すのはなぜですか (補足 - これgrepはループの外にある必要があります)。最初から良いノードを探すことができます! ループ全体を次のように置き換えます。

foreach my $a ( keys %$hash )
{
    @{ $hash->{$a}->{ds} } = grep { !/local/i } @{ $hash->{$a}->{ds} };
}
于 2012-10-31T15:08:14.320 に答える
1

あまりきれいではありませんが:

foreach my $a ( keys %$hash )
{
    my $temp;
    foreach ( @{ $hash->{$a}->{ds} } ) 
    {   
        push(@$temp, $_) unless $_ =~ /local/i;
    }
    $hash->{$a}->{ds} = $temp;
}

Delete は配列構造を変更しません。配列の内容を変更するだけです。メソッドでこのため、定義済みのエントリを grep して、必要な構造の新しい配列を作成し、古い配列を上書きする必要があります。

編集: これは、perldoc ページの削除でよりよく説明されています

delete() は配列と配列スライスにも使用できますが、その動作は単純ではありません。exists() は削除されたエントリに対して false を返しますが、配列要素を削除しても既存の値のインデックスは変更されません。そのためには shift() または splice() を使用してください。ただし、削除されたすべての要素が配列の最後にある場合、配列のサイズは、exists() が真であるとテストされる最上位の要素の位置に縮小されます。そうでない場合は 0 に縮小されます。

編集:

mob splice で指摘されているように、あなたが望むことを行います:

foreach my $a ( keys %$hash )
{
    for(0..$#{ $hash->{$a}->{ds} } ) 
    {   
        splice( @{ $hash->{$a}->{ds} }, $_, 1 ) if $hash->{$a}->{ds}->[ $_ ] =~ /local/i;
    }
}
于 2012-10-31T14:52:59.960 に答える
1
for my $h (values %$hash){
    $h->{ds} = [ grep { $_ !~ /local/i } @{$h->{ds}} ];
}
于 2012-10-31T15:06:54.620 に答える
0

List :: MoreUtils qw / first_idx /を使用して、/local/のインデックスを取得できます。

first_idx { $_ =~ /local/i } @{$hash->{$a}->{ds}};

次に、それを使ってやりたいことをします。

于 2012-10-31T15:00:04.433 に答える