是否有可能从Perl foreach循环中的数组中分配两个变量相同的数据?是否可以在Perl foreach循环中分配两个变量?
我使用Perl 5,我觉得我碰到的东西进来的Perl 6
事情是这样的:
my $var1;
my $var2;
foreach $var1,$var2 (@array){...}
是否有可能从Perl foreach循环中的数组中分配两个变量相同的数据?是否可以在Perl foreach循环中分配两个变量?
我使用Perl 5,我觉得我碰到的东西进来的Perl 6
事情是这样的:
my $var1;
my $var2;
foreach $var1,$var2 (@array){...}
这不是在Perl 5的核心语言,但List::Util有pairs
功能它应该足够接近(以及其他一些pair...
功能,这些功能可能更方便,这取决于您在回路内所做的操作):
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
use List::Util 'pairs';
my @list = qw(a 1 b 2 c 3);
for my $pair (pairs @list) {
my ($first, $second) = @$pair;
say "$first => $second";
}
输出:
a => 1
b => 2
c => 3
List :: Util是Perl 5.7.3以来的核心模块。所以可以假定为安装。 – BarneySchmale
@BarneySchmale - 是的,我不太清楚如何清楚地说出来。它是核心_distribution_(你不必从CPAN安装)的一部分,但不是核心_language_的一部分(你必须明确地使用模块)。我接受建议(或编辑)以更好的方式说出答案。 –
@BarneySchmale你可以依赖List :: Util,但不能在List :: Pairwise API中使用,它只在最近才添加。 – tchrist
超过2个变量的一般算法:
while(@array){
my $var1 = shift @array;
my $var2 = shift @array;
my $var3 = shift @array;
# other variables from @array
# do things with $var1, $var2, $var3, ...
}
PS:使用阵列的工作副本至其被保留供以后使用:
if(my @working_copy = @array){
while(@working_copy){
my $var1 = shift @working_copy;
my $var2 = shift @working_copy;
my $var3 = shift @working_copy;
# other variables from @working_copy
# do things with $var1, $var2, $var3, ...
}
}
PPS:另一种方法是使用索引。当然,这是数据结构错误的肯定标志。它应该是数组数组(AoA)或散列数组(AoH)。见perldoc perldsc和perldoc perllol。
my $i = 0;
while($i < @array){
my $var1 = $array[ $i++ ];
my $var2 = $array[ $i++ ];
my $var3 = $array[ $i++ ];
# other variables from @array
# do things with $var1, $var2, $var3, ...
}
PPPS:我被要求澄清为什么数据结构是错误的。它是一组扁平化的元组(又名记录又名数据集)。通过计数每个数据的数量来重新创建元组。但是构建这个集合的读者有什么错误,并不总能得到正确的数字?如果缺少一个值,它只是跳过添加任何东西?然后所有剩余的元组都被移位一个,导致以下元组被错误地分组,因此无效。这就是为什么AoA更好;只有包含缺失数据的元组无效。
但是更好的结构将是AoH。每个数据都可以通过一个密钥访问。然后可以添加新的或可选的数据而不会破坏下游代码。
,而我在这,我会添加一些代码示例:
# example code for AoA
for my $tuple (@aoa){
my $var1 = $tuple->[0];
my $var2 = $tuple->[1];
my $var3 = $tuple->[2];
# etc
}
# example code for AoH
for my $tuple (@aoh){
my $var1 = $tuple->{keyname1};
my $var2 = $tuple->{key_name_2};
my $var3 = $tuple->{'key name with spaces'};
my $var4 = $tuple->{$key_name_in_scalar_variable};
# etc
}
值得注意的是,在这个循环完成之后'@ array'将是空的。一个'foreach'循环没有这种副作用。 –
但是'foreach'循环不起作用。 – shawnhcorey
同意。我并不是说你的代码是坏的或者错误的,只是OP最初询问了一个“foreach”循环。你的解决方案和'foreach'循环之间的一个区别就是你的代码从数组中删除了项目。没有错,只是不同 - 因此“值得注意”。 –
最简单的方法来使用,这是一个while
循环调用每个时间数组的前两个元素splice
,
while (my($var1, $var2) = splice(@array, 0, 2)) {
...
}
然而,不同于foreach
,这种持续和原始数组上两班,所以当你完成,该数组为空。此外,分配的变量是副本,而不是别名,如foreach
。
如果你不喜欢,你可以使用C风格for
循环:
for (my $i = 0; $i < @array; $i += 2) {
my($var1, $var2) = @array[$i, $i+1];
...
}
这使得到位数组,但不允许更新它方式foreach
一样。要做到这一点,你需要直接访问数组。
my @pairlist = (
fee => 1,
fie => 2,
foe => 3,
fum => 4,
);
for (my $i = 0; $i < @pairlist; $i += 2) {
$pairlist[ $i + 0 ] x= 2;
$pairlist[ $i + 1 ] *= 2;
}
print "Array is @pairlist\n";
打印出:
Array is feefee 2 fiefie 4 foefoe 6 fumfum 8
您可以让那些到别名变量,如果你足够努力,但它可能不值得:
my @kvlist = (
fee => 1,
fie => 2,
foe => 3,
fum => 4,
);
for (my $i = 0; $i < @kvlist; $i += 2) {
our ($key, $value);
local(*key, $value) = \@kvlist[ $i, $i + 1 ];
$key x= 2;
$value *= 2;
}
print "Array is @kvlist\n";
哪打印出预期的更改阵列:
Array is feefee 2 fiefie 4 foefoe 6 fumfum 8
注意,由List::Pairwise模块提供的对,这不过是非常最近添加到核心List::Util模块(所以你可能无法使用),仍然没有给你的别名:
use List::Util 1.29 qw(pairs);
my @pairlist = (
fee => 1,
fie => 2,
foe => 3,
fum => 4,
);
for my $pref (pairs(@pairlist)) {
$pref->[0] x= 2;
$pref->[1] *= 2;
}
print "Array is @pairlist\n";
这只是打印出:
Array is fee 1 fie 2 foe 3 fum 4
因此,它并没有改变阵列的。哎呀。 :(
当然,如果这是一个真实的哈希,你可能会增加一倍平凡的值:
for my $value (values %hash) { $value *= 2 }
的作品的原因是因为那些是别名到实际的哈希值
你不能改变的钥匙,因为他们是不可改变的。然而,你可以做一个新的哈希那是旧足够容易的更新副本:
my %old_hash = (
fee => 1,
fie => 2,
foe => 3,
fum => 4,
);
my %new_hash;
@new_hash{ map { $_ x 2 } keys %old_hash } =
map { $_ * 2 } values %old_hash;
print "Old hash is: ", join(" " => %old_hash), "\n";
print "New hash is: ", join(" " => %new_hash), "\n";
输出
Old hash is: foe 3 fee 1 fum 4 fie 2
New hash is: foefoe 6 fiefie 4 fumfum 8 feefee 2
这里是一个模块,更少的方式来“循环”由任意的值($by
)和输出使用阵列片元件得到的基团:
#!perl -l
@array = "1".."6";
$by = 3; $by--;
for (my $i = 0 ; $i < @array ; $i += $by) {
print "@array[$i..$i+$by]";
$i++ ;
}
作为一衬垫试验(剪切和粘贴到Unix外壳):
perl -E '@array = "1".."6"; $by = 3; $by--;
for (my $i = 0 ; $i < @array ; $i += $by) {
say "@array[$i..$i+$by]"; $i++ }'
输出:
1 2 3
4 5 6
如果您制作$by = 2;
它将打印数字对。为了得到所得切片的特定元素,将其作为匿名数组访问:(,例如[@array[$i..$i+$by]]->[1]
)。
参见:
一些良好的反应存在,包括参考natatime
这是很容易使用。它也很容易实现 - 它实质上是对这里的回复中提到的解决方案的包装。
以下是不是最好的例子,但我已经使用autobox::Core
和由@array->natatime()
“方法” ;-)这样的:
use autobox::Core ;
sub autobox::Core::ARRAY::natatime {
my ($self, $by) = @_;
my @copy = @$self ;
my @array ;
push @array, [splice (@copy, 0, $by) ] while @copy ;
if (not defined wantarray) {
print "@{ $_ } \n" for @array ;
}
return wantarray ? @array : \@array;
}
的@copy
阵列是spliced
破坏性,但$self
(其是如何将@array
在自动包装方法->
箭头传递给函数)仍然存在。所以,我可以这样做:
my @dozen = "1" .. "12" ; # cakes to eat
@dozen->natatime(4) ; # eat 4 at time
my $arr_ref = @dozen->natatime(4) ; # make a reference
say "Group 3: @{ $arr_ref->[2] }" ; # prints a group of elements
say scalar @dozen , " cakes left" ; # eat cake; still have it
输出:
1 2 3 4
5 6 7 8
9 10 11 12
Group 3: 9 10 11 12
12 cakes left
一说还采用了CPAN模块另一种方法(我给this answer elsewhere但它是值得重复)。这也可以做非破坏性,具有优良Eric Strom's模块List::Gen
:
perl -MList::Gen=":all" -E '@n = "1".."6"; say "@$_" for every 2 => @n'
1 2
3 4
5 6
每次抢组元素中的匿名数组返回所以个人值是:$_->[0] $_->[1] ...
等。从2009年Perl6降临Looping for Fun and Profit:
你提到Perl6,这很好地处理多个循环值:
my @qarr = 1 .. 6;
my ($x, $y, $z) ;
for @qarr -> $x , $y , $z { say $x/$y ; say "z = " ~ $z }
输出:
0.5
z = 3
0.8
z = 6
欲了解更多的Perl6方法见日历或Blocks and Statements Synopsis以了解详情。也许Perl 5将有一个类似的“循环由多个值”构造一天 - àlaperl5i's foreach
:-)
你是否在寻找['each'](http://perldoc.perl.org/functions/ each.html)?它说明了while(($ key,$ value)= each%ENV)print {$ key = $ value \ n};其中包括智慧。谨防重置行为。另请参见[为什么Perl的'each'不是第二次遍历整个哈希?](http://stackoverflow.com/questions/1123693/why-doesnt-perls-each-iterate-through-the-entire- hash-the-second-time) –