4

この形式のハッシュの場合:

my $itemHash = {
    tag1 => {
        name => "Item 1",
        order => 1,
        enabled => 1,
    },
    tag2 => {
        name => "Item 2",
        order => 2,
        enabled => 0,
    },
    tag3 => {
        name => "Item 3",
        order => 3,
        enabled => 1,
    },
    ...
}

ハッシュを正しく反復する次のコードがあります。

keys %$itemHash; # Resets the iterator
while(my($tag, $item) = each %$itemHash) {
    print "$tag is $item->{'name'}"
}

ただし、これらのアイテムが繰り返される順序はかなりランダムなようです。同じwhile形式を使用して、各アイテムのハッシュの「order」キーで指定された順序でそれらを反復処理することは可能ですか?

(最初にキーを並べ替えてから、foreachループを実行できることを知っています。これを行うためのよりクリーンな方法があるかどうかを確認するだけです。)

4

4 に答える 4

11

次のようなことができます:

foreach my $key (sort keys %{$itemHash}) {
    print "$key : " . $itemHash->{$key}{name} . "\n";
}
于 2012-10-12T14:05:01.970 に答える
8

「順序付けられたハッシュ」の概念は間違っています。配列は要素の順序付きリストであるため、インデックスでアクセスできますが、ハッシュはキーと値のペアの(順序付けされていない)コレクションであり、キーはセットです。

タスクを実行するには、orderプロパティでキーを並べ替える必要があります。

my @sorted = sort {$hash{$a}{order} <=> $hash{$b}{order}} keys %$itemHash;

次に、次の方法でキーと値のペアを作成できますmap

my @sortedpairs = map {$_ => $itemHash->{$_}} @sorted;

これをサブにまとめることができます:

sub ridiculousEach {
  my %hash = @_;
  return map
      {$_ => $hash{$_}}
        sort
          {$hash{$a}{order} <=> $hash{$b}{order}}
             keys %hash;
}

Key-Value要素の均等なサイズのリストを取得するには、

sub giveIterator {
  my %hash = @_;
  my @sorted = sort {$hash{$a}{order} <=> $hash{$b}{order}} keys %hash;
  return sub {
     my $key = shift @sorted;
     return ($key => $hash{$key});
  };
}

それぞれのドロップインであるコールバックを作成します。

その後、次のことができます。

my $iterator = giveIterator(%$itemHash);
while (my ($tag, $item) = $iterator->()) {
  ...;
}

このアプローチには重大な欠点がありeachます。一度に2つの要素しか使用しないため、一定のメモリで動作します。このソリューションでは、ハッシュ全体を読み取り、すべてのキーの配列を格納する必要があります。小さなハッシュでは目立たないが、これは非常に大量の要素で重要になる可能性がある。

于 2012-09-25T23:57:54.190 に答える
5

ハッシュからのキーの順序は未定義です。したがって、キーを並べ替える必要があります。1つの方法は、あなたが述べたように、キーを引き出して並べ替えてから、キーをループすることです。

別の方法は、その場でそれらをソートすることです。でも、もっときれいだと思うかどうかはわかりません。何かのようなもの:

for my $key ( sort { $itemHash->{$a}{order} <=> $itemhash->{$b}{order} } keys %$itemHash ) {
  print "$key is $itemHash->{$key}{name}";
}
于 2012-09-25T23:55:45.153 に答える
2

これでかなりすっきりします。文字列のソートには cmp を使用する必要があります。

my $itemHash = {
    tag1 => {
        name => "Item 1",
        order => 1,
        enabled => 1,
    },
    tag2 => {
        name => "Item 2",
        order => 2,
        enabled => 0,
    },
    tag3 => {
        name => "Item 3",
        order => 3,
        enabled => 1,
    }
};

foreach((sort{$a cmp $b}(keys(%$itemHash)))){
print "$_ is $itemHash->{$_}->{'name'}\n";
}
于 2012-09-27T08:29:16.223 に答える