【发布时间】:2011-04-02 11:47:26
【问题描述】:
我想根据用户输入动态创建数组。例如,如果用户输入为 3,则应创建三个名称为 @message1、@message2 和 @message3 的数组。
如何在 Perl 中做到这一点?
【问题讨论】:
-
超级简短答案的机会:perllol。甚至 Perl 也有 LOLz。
我想根据用户输入动态创建数组。例如,如果用户输入为 3,则应创建三个名称为 @message1、@message2 和 @message3 的数组。
如何在 Perl 中做到这一点?
【问题讨论】:
不要。相反,使用数组数组:
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
【讨论】:
我不得不问你为什么要这样做,因为这不是正确的方法。如果你有三个输入流,每个输入流都需要存储为一个列表,然后存储 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)
关于为情况选择正确的数据结构,以及如何定义
他们。
【讨论】:
动态创建新的命名数组几乎从来都不是一个好主意。 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 中使用引用的更多详细信息,请参阅以下文档:
perldoc perlreftut
perldoc perlref
perldoc perldsc
【讨论】:
在编译语言中,变量没有名称。您在代码中看到的名称是与一些数字偏移相关联的唯一标识符。在像message_2 这样的标识符中,'2' 仅用于使其成为唯一标识符。任何人都知道你可以创建三个变量:message_125、message_216 和 message_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)