-4

谁能解释一下这个语句在 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;
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;

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

在这样做的同时,作者产生了可怕的代码。以下是可以做得更好的地方:

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

    my @grouped_products;
    push @grouped_products, ...;
    return \@grouped_products; # reference operator \
    
  • 在某些时候,分配了一个 hashref。这是不必要的,因为 Perl会自动激活用作散列或数组引用的未定义值。那条完整的线是没有用的。此外,仅当该值为 false 时才分配它。作者可能想要的是分配该值是否为undefined//此处可以使用定义或运算符(仅从 perl5 v10 或更高版本开始)。

  • 构建哈希哈希。这是浪费。数组的哈希会更好。
  • 如果使用foror循环值foreach,则不必将当前项目分配给 cryptic $_。相反,可以指定一个循环变量:foreach my $foo (@bar). 的默认行为foreach类似于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函数接受一个必须返回数字的块:“<code>$a 小于”为负数,“<code>$a 且相等”$b为零,或“<code>$a 大于”为正数$b$b”。

运算符按字典顺序比较cmp操作数。如果品牌不同,那么我们不必比较类型。如果品牌相同,则第一个cmp返回0,这是一个错误值。因此,执行第二个比较(类型),并返回该值。这是按主键和辅助键排序的标准 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哈希(待填充)。对于每个产品,我们将该产品的类型添加到分组哈希中相应品牌的数组引用中。也就是说,我们收集每个品牌的所有类型。我们定义了一个包含所有分组产品(待填充)的数组。我们按字母顺序遍历所有品牌,然后按字母顺序遍历该品牌的所有独特产品。对于这些品牌/类型组合中的每一个,我们都会为分组的产品添加一个新的 hashref。该uniq功能是从优秀的List::MoreUtils模块中导入的。我们返回对分组产品数组的引用。

于 2013-02-12T17:14:54.147 回答