为什么1分配给哈希元素?

时间:2013-02-12 12:05:54

标签: perl perl-data-structures perl-hash

任何人都可以解释这句话在Perl中的作用吗

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

我可以理解哈希%type有一个键brand持有对另一个哈希brand的引用, 1分配给它

这是什么意思?? !!!何时将其指定为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;

1 个答案:

答案 0 :(得分:1)

代码

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

表示:

  • 我们有一个类型为hash的变量,名为%hash
  • 主题变量 $_包含散列的参考
  • 我们在brand引用的哈希中访问名为$_的条目。我们记得这个价值。
  • 我们在名为%hash的哈希中使用我们刚刚记住的名称访问该条目。
  • 哈希元素是左值,即可以分配给它们。
  • 我们将号码1分配到我们刚刚访问的哈希槽中。

注意事项:

  • 在Perl中,哈希是一种数据结构。其他语言将此视为关联数组。它将字符串映射到标量值。
  • 哈希函数计算给定字符串的特征数。散列数据结构在内部使用这样的函数,并且以Perl无法访问的方式。哈希函数在加密中也很重要。
  • =运算符将右侧的东西分配给左侧的东西。
  • 该行代码没有一个关键字,只有变量(%type$_),常量('brand'1)和运算符({{1} },{...}->=)。

以下是您在评论中发布的代码,注释时带注释:

;

这段代码有什么作用?它需要所有产品(产品是包含品牌和类型字段的hashref),并且主要按品牌进行排序,其次按类型,按字母顺序,按升序排序。

这样做时,作者制作了可怕的代码。这可能会变得更好:

  • 他使用的是arrayref而不是数组。使用数组会更容易,并返回对它的引用:

    # 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;
    
  • 在某些时候,分配了hashref。这是不必要的,因为Perl 自动生成用作散列或数组引用的未定义值。那条完整的路线毫无用处。此外,仅在该值为false时才分配。作者可能想要的是分配该值是否为 undefined 。这里可以使用已定义的或运算符my @grouped_products; push @grouped_products, ...; return \@grouped_products; # reference operator \ (仅限于perl5 v10或更高版本)。

  • 构建哈希哈希。这很浪费。数组的哈希会更好。
  • 如果使用//for循环覆盖值,则当前项目不会分配给隐藏foreach。相反,可以指定循环变量:$_foreach my $foo (@bar)的默认行为类似于foreach
  • 隐性回报很糟糕。

这是一段实现相同子程序的代码,但更多的是perlish - 记住,我们只想对产品进行排序(假设它们已经是唯一的)

foreach 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的负数小于$a”,“$b$a为0相等“,或”$b的正数大于$a“。

$b运算符以lexigraphically方式比较操作数。如果品牌不同,那么我们不必比较类型。如果品牌相同,则第一个cmp会返回cmp,这是一个假值。因此,执行第二个比较(类型),并返回该值。这是用于按主键和辅助键排序的标准Perl习语。

0sort级联从右/下到左/上执行。

如果不能保证唯一性,那么这样的事情会更好:

map

说明:我们定义一个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; } 哈希(待填充)。对于每个产品,我们将该产品的类型添加到分组哈希中相应品牌的arrayref。也就是说,我们收集每个品牌的所有类型。我们定义了所有分组产品的数组(待填充)。我们按字母顺序遍历所有品牌,然后按字母顺序遍历该品牌的所有独特产品。对于这些品牌/类型组合中的每一种,我们将新的hashref添加到分组产品中。 %grouping函数是从优秀的uniq模块导入的。我们返回对分组产品数组的引用。