【问题标题】:Creating arrays dynamically in Perl在 Perl 中动态创建数组
【发布时间】:2011-04-02 11:47:26
【问题描述】:

我想根据用户输入动态创建数组。例如,如果用户输入为 3,则应创建三个名称为 @message1@message2@message3 的数组。

如何在 Perl 中做到这一点?

【问题讨论】:

  • 超级简短答案的机会:perllol。甚至 Perl 也有 LOLz。

标签: arrays perl


【解决方案1】:

不要。相反,使用数组数组:

my @message;
my $input = 3;
for my $index ( 0..$input-1 ) {
    $message[$index][0] = "element 0";
    $message[$index][1] = 42;
}
print "The second array has ", scalar( @{ $message[1] } ), " elements\n";
print "They are:\n";
for my $index ( 0..$#{ $message[1] } ) {
    print "\t", $message[1][$index], "\n";
}

一些有用的规则在http://perlmonks.org/?node=References+quick+reference

【讨论】:

    【解决方案2】:

    我不得不问你为什么要这样做,因为这不是正确的方法。如果你有三个输入流,每个输入流都需要存储为一个列表,然后存储 one list,这是一个列表的列表(其中列表存储为 array 引用):

    my @input = (
        [ 'data', 'from', 'first', 'user' ],
        [ qw(data from second user) ],
        [ qw(etc etc etc) ],
    );
    

    如果您有与每个用户数据相关联的名称,您可能希望使用该名称 作为哈希键,用于索引数据:

    my %input = (
        senthil => [ 'data', 'from', 'first', 'user' ],
        ether => [ qw(data from second user) ],
        apu => [ qw(etc etc etc) ],
    );
    

    更多信息请参考Perl Data Structures Cookbook (perldoc perldsc) 关于为情况选择正确的数据结构,以及如何定义 他们。

    【讨论】:

    • 很好的答案——除了当你的意思是“数组”时,你多次提到“列表”。在 Perl 中,列表和数组不是一回事。列表是数据,数组是变量。区别很微妙,但很重要。
    • @davorg:当我说列表时,我指的是列表。列表可以存储为 arraysarrayrefs,也可以存储在 hashes 中。
    • 不,不是。数组或散列可以生成列表或从列表初始化,但它们并不完全存储列表。我仍然会给“存储在数组中的列表”一个通行证,但是“将列表存储为 as 一个数组”太误导了。
    【解决方案3】:

    动态创建新的命名数组几乎从来都不是一个好主意。 Mark Dominus,启蒙书籍Higher-Order Perl 的作者,写了一封three-partseries,详细说明了这些陷阱。

    您已经为这些数组记住了名称,因此将它们放在哈希中:

    sub create_arrays {
      my($where,$n) = @_;
    
      for (1 .. $n) {
        $where->{"message$_"} = [];
      }
    }
    

    对于显示结构的快速示例,下面的代码

    my $n = @ARGV ? shift : 3;
    
    my %hash;
    create_arrays \%hash, $n;
    
    use Data::Dumper;
    $Data::Dumper::Indent = $Data::Dumper::Terse = 1;
    print Dumper \%hash;
    

    输出

    $ ./prog.pl
    {
      'message2' => [],
      'message3' => [],
      '消息1' => []
    }

    指定不同数量的数组,我们得到

    $ ./prog.pl 7
    {
      'message2' => [],
      'message6' => [],
      'message5' => [],
      'message4' => [],
      'message3' => [],
      'message1' => [],
      '消息7' => []
    }

    键的顺序看起来很有趣,因为它们在散列中,一个无序的数据结构。

    回想一下,[] 创建了一个对新匿名数组的引用,因此,例如,要向 message2 添加值,您可以这样写

    push @{ $hash{"message2"} }, "Hello!";
    

    要打印它,你会写

    print $hash{"message2"}[0], "\n";
    

    也许您想知道所有数组的长度:

    foreach my $i (1 .. $n) {
      print "message$i: ", scalar @{ $hash{"message$i"} }, "\n";
    }
    

    有关如何在 Perl 中使用引用的更多详细信息,请参阅以下文档:

    【讨论】:

      【解决方案4】:

      在编译语言中,变量没有名称。您在代码中看到的名称是与一些数字偏移相关联的唯一标识符。在像message_2 这样的标识符中,'2' 仅用于使其成为唯一标识符。任何人都知道你可以创建三个变量:message_125message_216message_343。只要你能说出你应该把什么放进去,它们的效果就和message_1...

      变量的“名称”仅供您在编写代码时保持它们的正确性。

      动态语言通过不清除符号表来增加功能。但是符号表只是名称与值的关联。由于 Perl 为您提供列表和散列的成本非常低廉,因此无需使用编程/逻辑方法来跟踪变量以实现灵活的运行时访问。

      如果您看到自己命名列表 @message1@message2、... ——其中项目仅因引用顺序不同而不同,那么这些名称可能同样好:$message[1]$message[2] , ....

      此外,由于符号表通常是从名称到偏移量的映射(在堆栈上或在堆中),它实际上并不比您在 散列中找到的键值对多很多。因此,哈希对于查找更多不同的名称同样有效。

      $h{messages} = [];
      $h{replies}  = [];
      

      我的意思是,如果您愿意,您可以将放入词法变量的所有内容存储到作用域的单个哈希中,如果您不介意写:$h{variable_name} 用于所有内容。但是您不会从 Perl 的隐式范围管理中受益,而且跨语言,程序员更喜欢隐式范围管理。

      Perl 允许符号操作,但多年来动态语言发现这是喜忧参半。但是在 Perl 中,你有两个“观点”,给他们一个名字。因为您可以确定编译语言中的哪些代码可能比动态语言做得更好,所以已经确定使用“编译透视图”处理更多事情时不会出错:因此,您可以看到偏移管理的可用性并查找核心 Perl 中提供给您的编译行为,如果您不需要,没有理由弄乱符号表。

      动态创建数组很简单:[]。当我们不知道要存储多少时,将其分配到内存中的某个位置很简单:

      push @message, [];
      

      同时创建一个列表非常简单:

      @message = map { [] } 1..$num_lists;
      

      $num_lists 中的某个指定值。

      【讨论】:

      • ([])x 创建同一个数组引用的多个副本;你想要map([],1..$num_lists)
      • @ysth,你知道,我先用地图写了它,但认为乘数看起来更快。 :)
      猜你喜欢
      • 2017-06-01
      • 1970-01-01
      • 2015-01-06
      • 2015-11-15
      • 2014-04-13
      • 2019-12-14
      • 2012-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多