Perl 散列数组

Perl 散列数组,perl,hash,Perl,Hash,在perl中,我有一个哈希数组 像 现在我需要在标题和作者相同的情况下累加数量。 在上面的title=1177和author='ABC'散列结构中,数量可以累加为一个,整个结构如下所示 0 HASH(0x98335e0) 'title' => 1177 'author' => 'ABC' 'quantity' => 0 1 HASH(0x98335e0) 'title' => 1127 'author' => 'DEF' '

在perl中,我有一个哈希数组 像

现在我需要在标题和作者相同的情况下累加数量。 在上面的title=1177和author='ABC'散列结构中,数量可以累加为一个,整个结构如下所示

0  HASH(0x98335e0)
   'title' => 1177
   'author' => 'ABC'
   'quantity' => 0

1  HASH(0x98335e0)
   'title' => 1127
   'author' => 'DEF'
   'quantity' => '5100'

2  HASH(0x832a9f0)
   'title' => 1277
   'author' => 'XYZ'
   'quantity' => '1030'
我可以用什么样的最佳方式来进行这种积累,以使其得到优化?数组元素的数量可能非常大。我不介意在散列中添加一个额外的键来帮助相同的操作,但是我不想进行n次查找。恳请告知

my %sum;
for (@a) {
  $sum{ $_->{author} }{ $_->{title} } += $_->{quantity};
}

my @accumulated;
foreach my $author (keys %sum) {
  foreach my $title (keys %{ $sum{$author} }) {
    push @accumulated => { title    => $title,
                           author   => $author,
                           quantity => $sum{$author}{$title},
                         };
  }
}
不确定
map
是否会让它看起来更好:

my @accumulated =
  map {
    my $author = $_;
    map { author   => $author,
          title    => $_,
          quantity => $sum{$author}{$_},
        },
      keys %{ $sum{$author} };
  }
  keys %sum;

如果不需要N个查找,那么需要一个哈希函数——不过需要用该哈希函数存储它们。当您将它们放入列表(或数组)时,已经太晚了。你要么一直都很幸运,,要么就会有N次查找

将它们插入下面的散列中。混合解决方案是将定位器存储为列表/数组中的项0

my $lot = get_lot_from_whatever();
my $tot = $list[0]{ $lot->{author} }{ $lot->{title} };
if ( $tot ) { 
    $tot->{quantity} += $lot->{quantity};
}
else { 
    push @list, $list[0]{ $lot->{author} }{ $lot->{title} } = $lot;
}        

先前的

首先,我们将对其进行重新格式化以使其可读

[ { title => 1177, author => 'ABC', quantity => '-100' }
, { title => 1177, author => 'ABC', quantity => '100'  }
, { title => 1127, author => 'DEF', quantity => '5100' }
, { title => 1277, author => 'XYZ', quantity => '1030' }
]
接下来,您需要分解问题。你想把大量的东西分组 按作者和标题。所以你需要这些东西来唯一地识别那些地段。 要重复,您需要一组名称来标识实体。因此,你 将需要一个按名称标识事物的哈希

因为我们有两件事,所以双哈希是一种很好的方法

my %hash;
foreach my $lot ( @list ) {
    $hash{ $lot->{author} }{ $lot->{title} } += $lot->{quantity};
}
# consolidated by hash
要将其返回到列表中,我们需要分解级别

my @consol
    = sort { $a->{author} cmp $b->{author} || $a->{title} cmp $b->{title} }
      map  { 
          my ( $a, $titles ) = @$_; # $_ is [ $a, {...} ]
          map { +{ title => $_, author => $a, quantity => $titles->{$_} }
          keys %$titles;
      } 
      map  { [ $_ => $hash{$_} ] } # group and freeze a pair
      keys %hash
    ;

# consolidated in a list.
你拿回来了,我甚至帮你整理好了。当然你也可以 按出版商是什么来排序,数量递减

sort {  $b->{quantity} <=> $a->{quantity} 
     || $a->{author}   cmp $b->{author} 
     || $a->{title}    cmp $b->{title} 
     }
sort{$b->{quantity}$a->{quantity}
||$a->{author}cmp$b->{author}
||$a->{title}cmp$b->{title}
}

我认为退一步考虑数据的来源是很重要的。如果数据来自数据库,则应编写SQL查询,以便为每个作者/标题组合提供一行,并在数量字段中显示总数量。如果您正在从文件中读取数据,那么您应该将其直接读取到散列中,或者在顺序重要时使用


一旦像您这样将数据放入一个hashref数组中,您就必须创建一个辅助数据结构并进行一系列查找,其成本可能会主导程序的运行时间(如果每天运行一次15分钟并不重要),并且您可能会遇到内存问题。

“我不需要n次查找”,但是如果不访问数组的每个成员,就无法在整个数组中累积。请将和添加到您的阅读列表中。此示例只是想获得一些map/greplove@Daenyth通常是的,但在这种情况下看起来不太好。
sort {  $b->{quantity} <=> $a->{quantity} 
     || $a->{author}   cmp $b->{author} 
     || $a->{title}    cmp $b->{title} 
     }