何时在Perl中使用数组而不是散列更好?

时间:2014-08-14 17:07:19

标签: arrays perl hash

假设你有一个数组@a = qw/ a b c d/;

和哈希%a = ('a' => 1, 'b' => 1, 'c' => 1, 'd' => 1);

是否有任何情况下创建数组版本比创建哈希更好(除非必须迭代所有值,如

for (@a){
    ....

在这种情况下,如果使用散列,则必须使用keys %a?因为测试特定值是否在散列中总是比在数组中这样做更有效,所以更正吗?

4 个答案:

答案 0 :(得分:8)

    • 数组按数字编制索引。
    • 哈希用字符串键入。
    • 最高索引的所有索引都存在于数组中。
    • 哈希被稀疏索引。 (例如,“a”和“c”可以在没有“b”的情况下存在。)
  1. 有许多新兴属性。首先,

      • 数组可用于存储有序列表。
      • 以这种方式使用哈希是一种效率低下的效率。
      • 除非它是最高的索引元素,否则无法从数组中删除元素。
      • 您可以从使用数组实现的有序列表中删除,但删除第一个或最后一个元素以外的元素效率很低。
      • 可以从哈希中删除一个元素,效率很高。

答案 1 :(得分:3)

数组是有序的值列表。它们可以包含重复值。

@array = qw(a b c a);

哈希是密钥(必须是唯一的)和值(可以复制)之间的映射。哈希(有效地)无序,这意味着密钥以明显随机的顺序而不是输入的顺序出现。

%hash = (a => 1, b => 2, c => 3);

只有关键很重要时,哈希也可以用作集合。集合是无序的,只包含唯一的“值”(散列键)。

%set = (a => undef, b => undef, c => undef);

使用哪一个取决于您的数据和算法。在订单很重要时使用数组(特别是如果您无法排序以获取订单)或者可能存在重复值。当值必须唯一且不关心顺序时,使用集合(即使用散列作为集合)。当唯一性很重要时使用哈希,顺序不(或很容易排序),查找基于任意值而不是整数。

您可以组合数组和散列(通过引用)来创建任意复杂的数据结构。

@aoa = ([1, 2, 3], [4, 5, 6]);               # array of arrays ("2D" array)
%hoh = (a => { x => 1 }, b => { x => 2 });   # hash of hashes
@aoh = ({a => 1, b => 2}, {a => 3, b => 4}); # array of hashes
%hoa = (a => [1, 2], b => [3, 4]);           # hash of arrays
...etc.

答案 2 :(得分:2)

这是关于使用数字作为哈希键。它并没有直接回答这个问题,因为它没有比较数组提供的设施,但我认为这是放置信息的好地方。

假设使用像这样的代码构建具有十个元素的哈希

use strict;
use warnings;

my %hash;
my $n = 1000;
for (1 .. 10) {
  $hash{$n} = 1;
  $n *= 1000;
}

然后我们查询它,寻找10的幂的密钥。当然,将整数乘以10的最简单方法是添加零,因此可以写

my $m = '1';

for (1 .. 100) {
  print $m, "\n" if $hash{$m};
  $m .= 0;
}

有输出

1000
1000000
1000000000
1000000000000
1000000000000000
1000000000000000000

我们输入了十个元素,但这只显示了六个元素。发生了什么事?我们来看看哈希中的内容。

use Data::Dump;
dd \%hash;

并输出

{
  "1000"                => 1,
  "1000000"             => 1,
  "1000000000"          => 1,
  "1000000000000"       => 1,
  "1000000000000000"    => 1,
  "1000000000000000000" => 1,
  "1e+021"              => 1,
  "1e+024"              => 1,
  "1e+027"              => 1,
  "1e+030"              => 1,
}

因此哈希不会使用我们想象的密钥。它以一种试图模仿的愚蠢方式对数字进行字符串化。

对于一个稍微更实际的例子,假设我们有一些圈子,并希望按区域收集。显而易见的是将该区域用作哈希键,就像这个程序一样,可以创建100,000个随机整数直径高达1800万的圆圈。

use strict;
use warnings;
use 5.010;

package Circle;

use Math::Trig 'pi';

sub new {
  my $class = shift;
  my $self = { radius => shift };
  bless $self, $class;
}

sub area {
  my $self = shift;
  my $radius = $self->{radius};
  pi * $radius * $radius;
}



package main;

my %circles;

for (1 .. 100_000) {
   my $circle = Circle->new(int rand 18_000_000);
   push @{ $circles{$circle->area} }, $circle;
}

现在让我们看看有多少哈希键使用科学记数法

say scalar grep /e/, keys %circles;

说(当然是随机的)

861

因此,如果我们将数字指定为哈希索引,那么确实不知道 string perl将使用什么的整洁方式。

答案 3 :(得分:1)

在Perl中,@array是由整数(正数和负数)访问的值($v1, $v2, ...)的有序列表, 而%hash是'key =>的无序列表通过字符串访问的值'(k1 => $v1, k2 => $v2, ...)

CPAN上有模块实现有序哈希,例如:Hash::OrderedTie::IxHash

你可能想要使用一个数组,当你订购'items'时可能也是一个很好的数字 使用%哈希并对键和/或值进行排序将是低效的。