-4

このステートメントが Perl で何をするのか説明できる人はいますか

$type{$_->{brand}} = 1;

ハッシュには別のハッシュへの参照を保持%typeするキーがあり、それに1が割り当てられていることがわかりましたbrandbrand

どういう意味ですか??!!!1として割り当てられたとき?

package SillyFunction;

sub group_products {
    my $products = shift;
    my %brand_type = ();
    my $grouped_products = [];

    foreach (@{$products}) {
        $brand_type{ $_->{brand} } ||= {};
        $brand_type{ $_->{brand} }->{ $_->{type} } = 1;
    }

    foreach (sort keys %brand_type) {
        my $brand = $_;
        foreach (sort keys %{ $brand_type{$brand} }) {
            push(@{$grouped_products}, { brand => $brand, type => $_ });
        }
    }

    $grouped_products;
}
1;
4

1 に答える 1

1

コード

$type{$_->{brand}} = 1;

意味:

  • という名前のハッシュ型の変数があります%hash
  • トピック変数 には、ハッシュへの参照$_が含まれています。
  • brandによって参照されるハッシュで呼び出されるエントリにアクセスします$_。この値を覚えています。
  • という名前のハッシュで覚えたばかりの名前でエントリにアクセスします%hash
  • ハッシュ要素は左辺値です。つまり、何かを割り当てることができます。
  • 1先ほどアクセスしたハッシュ スロットに番号を割り当てます。

注意点:

  • Perl では、ハッシュはデータ構造です。他の言語は、これを連想配列として認識しています。文字列をスカラー値にマップします。
  • ハッシュ関数は、特定の文字列の特性数を計算します。ハッシュ データ構造は、そのような関数を内部で使用し、Perl からアクセスできない方法で使用します。ハッシュ関数も暗号化において重要です。
  • オペレーターは右側の=ものを左側のものに割り当てます。
  • そのコード行には単一のキーワードはなく、変数 ( %type$_)、定数 ( 'brand'、 ) 、1および演算子 ( {...}->、) のみが含まれています。=;

コメントで注釈を付けて、コメントに投稿したコードは次のとおりです。

# Declare a namespace "SillyFunction".
# This affects the full names of the subroutines, and some variables.
package SillyFunction;

# Declare a sub that takes one parameter.
sub group_products {
  my $products = shift;

  my %brand_type = ();       # %brand_type is an empty hash.
  my $grouped_products = []; # $grouped_products is a reference to an array

  # loop through the products.
  # The @{...} "dereferences" an arrayref to an ordinary array
  # The current item is in the topic variable $_
  foreach (@{$products}) {
    # All the items in $products are references to hashes.
    # The hashes have keys "brand" and "type".

    # If the entry if %brand_type with the name of $_->{brand} is false,
    # Then we assign an empty hashref.
    # This is stupid (see discussion below)
    $brand_type{$_->{brand}} ||= {};

    # We access the entry names $_->{brand}.
    # We use that value as a hashref, and access the entry $_->{type} in there.
    # We then assign the value 1 to that slot.
    $brand_type{$_->{brand}}->{$_->{type}} = 1;
  }

  # We get the names of all entries of %brand_type with the keys function
  # We sort the names alphabetically.
  # The current key is in $_
  foreach (sort keys %brand_type) {
    # We assign the current key to the $brand variable.
    # This is stupid.
    my $brand = $_;

    # We get all the keys of the hash referenced by $brand_type{$brand}
    # And sort that again.
    # The current key is in $_
    foreach (sort keys %{$brand_type{$brand}}) {
      # We dereference the ordinary array from the arrayref $grouped_products.
      # We add a hashref to the end that contains entries for brand and type
      push(@{$grouped_products}, { brand => $brand, type => $_});
    }
  }

  # We implicitly return the arrayref containing all brands and types.
  $grouped_products;
}

# We return a true value to signal perl that this module loaded all right.
1;

このコードは何をしますか? すべての製品 (製品は、ブランドとタイプのフィールドを含むハッシュリファレンスです) を取得し、それらを主にブランドで、次にタイプで、アルファベットの昇順で並べ替えます。

そうしているうちに、作者は恐ろしいコードを作成しました。これがより良くなった可能性があるものです:

  • 彼は配列の代わりに arrayref を使用します。配列を使用して、それへの参照を返す方が簡単だったでしょう。

    my @grouped_products;
    push @grouped_products, ...;
    return \@grouped_products; # reference operator \
    
  • ある時点で、ハッシュリファレンスが割り当てられます。Perl は、ハッシュまたは配列参照として使用する未定義の値を自動有効化するため、これは不要です。その完全な行は役に立ちません。また、その値が false の場合にのみ割り当てられます。作成者がおそらく望んでいたのは、その値がundefinedである場合に割り当てることです。ここで defined-or 演算子//を使用できました (perl5 v10 以降のみ)。

  • ハッシュのハッシュが構築されます。これは無駄です。配列のハッシュの方が優れていたでしょう。
  • forまたはで値をループする場合、現在の項目を不可解な に割り当てる必要foreachありません。代わりに、ループ変数を指定できます: . のデフォルトの動作は に似ています。$_foreach my $foo (@bar)foreachforeach local $_ (@bar)
  • 暗黙のリターンは悪いです。

以下は、同じサブルーチンを実装するコードの一部ですが、よりパーリーです — 覚えておいてください、製品をソートしたかっただけです (製品が既に一意であると仮定します)。

sub group_products {
  my ($products) = @_;
  my @grouped =
    # sort by brand. If that is a draw, sort by type.
    sort { $a->{brand} cmp $b->{brand} or $a->{type} cmp $b->{type} }
    map  { +{%$_} } # make a copy.
    @$products;     # easy dereference
  return \@grouped;
}

説明:このコードは、大部分が自己文書化されています。このsort関数は、数値を返さなければならないブロックを取ります。「<code>$a がより小さい$b」の場合は負、「<code>$a と等しい」の場合はゼロ、「$b<code>$a が大きい場合」の場合は正のいずれかです。 」より$b

演算子はcmpオペランドを辞書的に比較します。ブランドが異なれば、タイプを比較する必要はありません。ブランドが同じである場合、最初の結果は をcmp返しますが0、これは偽の値です。したがって、2 番目の比較 (型) が実行され、その値が返されます。これは、主キーと副キーでソートするための標準の Perl イディオムです。

sortandmapカスケードは、右/下から左/上に実行されます。

一意性が保証されていない場合は、次のようなものがうまく機能します。

use List::MoreUtils qw/uniq/;
sub group_products {
  my ($products) = @_;
  my %grouping;
  push @{ $grouping{ $_->{brand} } }, $_->{type} for @$products;
  my @grouped;
  for my $brand (sort keys %grouping) {
    push @grouped, +{brand => $brand, type => $_} for sort uniq @{ $grouping{$brand} };
  }
  return \@grouped;
}

説明:ハッシュを定義し%groupingます (埋められる)。製品ごとに、その製品のタイプをグループ化ハッシュ内の適切なブランドの arrayref に追加します。つまり、各ブランドのすべてのタイプを収集します。グループ化されたすべての製品の配列を定義します (入力されます)。すべてのブランドをアルファベット順に繰り返し、次にそのブランドのすべてのユニークな製品をアルファベット順に繰り返します。これらのブランド/タイプの組み合わせごとに、グループ化された製品に新しいハッシュリファレンスを追加します。機能はuniq優れたList::MoreUtilsモジュールからインポートされます。グループ化された製品の配列への参照を返します。

于 2013-02-12T17:14:54.147 に答える