Arrays 在Perl中,什么时候使用数组而不是哈希更好?

Arrays 在Perl中,什么时候使用数组而不是哈希更好?,arrays,perl,hash,Arrays,Perl,Hash,假设你有一个数组@a=qw/a b c d/ 和散列%a=('a'=>1,'b'=>1,'c'=>1,'d'=>1) 是否存在创建数组版本比创建散列更好的情况(除了必须迭代所有值,如 for (@a){ .... 在这种情况下,如果使用哈希,则必须使用键%a)?因为测试特定值是否在散列中总是比在数组中更有效,对吗 数组由数字索引 哈希由字符串设置键 数组中存在最高索引的所有索引 散列索引很少。(例如,“a”和“c”可以在没有“b”的情况下存在。) 有许多紧急属性。主要是

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

和散列
%a=('a'=>1,'b'=>1,'c'=>1,'d'=>1)

是否存在创建数组版本比创建散列更好的情况(除了必须迭代所有值,如

for (@a){
    ....
在这种情况下,如果使用哈希,则必须使用
键%a
)?因为测试特定值是否在散列中总是比在数组中更有效,对吗

    • 数组由数字索引
    • 哈希由字符串设置键
    • 数组中存在最高索引的所有索引
    • 散列索引很少。(例如,“a”和“c”可以在没有“b”的情况下存在。)
  • 有许多紧急属性。主要是

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

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

    @array = qw(a b c a);
    
    散列是键(必须是唯一的)和值(可以复制)之间的映射。散列(实际上)是无序的,这意味着密钥的出现顺序显然是随机的,而不是它们的输入顺序

    %hash = (a => 1, b => 2, c => 3);
    
    当只有键重要时,哈希也可以用作集合。集合是无序的,只包含唯一的“值”(散列的键)

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

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

    @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.
    

    这是关于使用数字作为散列键的。它没有直接回答这个问题,因为它没有比较阵列提供的功能,但我认为它将是一个放置信息的好地方

    假设一个包含十个元素的散列是使用如下代码构建的

    use strict;
    use warnings;
    
    my %hash;
    my $n = 1000;
    for (1 .. 10) {
      $hash{$n} = 1;
      $n *= 1000;
    }
    
    然后我们查询它,寻找十次幂的键。当然,将一个整数乘以十的最简单方法是加一个零,所以写起来很好

    my $m = '1';
    
    for (1 .. 100) {
      print $m, "\n" if $hash{$m};
      $m .= 0;
    }
    
    哪个有输出

    1000
    1000000
    1000000000
    1000000000000
    1000000000000000
    1000000000000000000
    
    我们输入了十个元素,但这只显示了六个。发生了什么事?让我们看一下哈希中的内容。< /P>
    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,
    }
    
    所以散列没有使用我们想象的键。它以一种试图模仿的愚蠢方式对数字进行严格限制

    举一个稍微实际一点的例子,假设我们有一些圆,希望按面积收集成一组。最明显的是将区域用作散列键,就像这个程序创建100000个圆,随机整数直径高达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;
    
    上面说(当然是随机的)


    因此,如果我们指定一个数字作为散列索引,实际上没有一种清晰的方法来知道perl将使用什么字符串。

    在perl中,
    @array
    是一个由整数(正数和负数)访问的有序值列表, %hash是一个无序的“key=>value”对列表
    (k1=>$v1,k2=>$v2,…)
    ,由字符串访问

    CPAN上有一些模块实现有序散列,如:和

    例如,当您订购了大量的“项目”时,您可能希望使用数组
    使用%散列并对键和/或值进行排序将是低效的。

    散列键没有预测性排序,因此它与数组完全不同。如果这个问题被解决了,那将是一件很遗憾的事情。我认为这是一个很好的问题,它的答案会帮助很多人。可能是@ThisSuiteisBlacknot的重复,它不是链接问题的重复。链接问题询问
    $x{$i}
    是否真的比
    $x[$i]
    快。(不是。)这与泰勒的问题无关。在某些情况下,你应该使用散列的另一个原因是“数组是值的有序列表”。与散列一样。e、 g.
    $a[2]=“a”$a[0]=“b”$a[1]=“c”;打印值(@a)
    不会给出比
    $h{2}=“a”更多的
    abc
    $h{0}=“b”$h{1}=“c”;打印值(%h)将。这些值只是设置了键,您可以对数组和散列的键进行排序。实际上,区别在于对数组的键进行排序更有效。(在您提到
    push
    pop
    之前,请记住,您可以很容易地使
    push
    pop
    适用于散列。)@ikegami:当然,数组是有序的。您的
    @a
    将始终打印为
    bca
    。它们是按索引排序的。我从来没有说过它们的排序是基于插入的。要么重复我已经说过的(你可以对索引排序),要么你说散列也是按桶索引排序的。(别忘了散列的核心是一个数组。“散列”一词来源于这样一个事实,即该键被散列成一个数字,用作该数组的索引。)是的,散列是有序的,但该顺序对程序员来说是隐藏的,可能会在不通知的情况下更改。从Perl 5.18开始,散列顺序是随机的,并且在同一程序的两次执行之间不会相同。这就是为什么我说散列是有效的
    say scalar grep /e/, keys %circles;
    
    861