如何在Perl中同时迭代多个列表?

时间:2009-05-04 23:08:37

标签: perl arrays list

我需要创建一个文本文件(aptest.s),我可以用来读入另一个程序。我正在使用Perl,因为我有一个很大的列表可供使用。我的代码如下(它没有给出所需的输出 - 显示在代码和实际输出之后)。任何帮助将不胜感激。

#!/usr/bin/perl -w
chdir("D://projects//SW Model ODME");
@link = ("319-116264||319-118664","320-116380||320-116846","321-119118||321-119119","322-115298||322-119087");
@link1 = ("116264-319||118664-319","116380-320||116846-320","119118-321||119119-321","115298-322||119087-322");
open (FSAS, ">>aptest.s");
foreach $link (@link) {
    foreach $link1 (@link1){
    print FSAS "other code \n";
    print FSAS "PATHLOAD SELECTLINK=(Link=".$link."), VOL[2]=MW[1] \n";
    print FSAS "PATHLOAD SELECTLINK=(Link=".$link1."), VOL[3]=MW[2] \n";
    print FSAS "other code \n";
}
}

实际输出

other output
PATHLOAD SELECTLINK=(Link=319-116264||319-118664), VOL[2]=MW[1] 
PATHLOAD SELECTLINK=(Link=116264-319||118664-319), VOL[3]=MW[2] 
other output 

other output
PATHLOAD SELECTLINK=(Link=**319-116264||319-118664**), VOL[2]=MW[1] 
PATHLOAD SELECTLINK=(Link=**116380-320||116846-320**),      VOL[3]=MW[2] 
other output

所需输出

other output
PATHLOAD SELECTLINK=(Link=319-116264||319-118664), VOL[2]=MW[1] 
PATHLOAD SELECTLINK=(Link=116264-319||118664-319), VOL[3]=MW[2] 
other output

other output
PATHLOAD SELECTLINK=(Link=**320-116380||320-116846**), VOL[2]=MW[1] 
PATHLOAD SELECTLINK=(Link=**116380-320||116846-320**), VOL[3]=MW[2] 
other output

4 个答案:

答案 0 :(得分:21)

请参阅List::MoreUtils中的 each_array

#!/usr/bin/perl

use strict;
use warnings;

use List::MoreUtils qw( each_array );

my @x = qw( A B C D E F );
my @y = (10, 11, 12, 13, 14, 15);

my $it = each_array( @x, @y );
while ( my ($x, $y) = $it->() ) {
    print "$x = $y\n";
}
__END__

答案 1 :(得分:4)

认为你正在尝试创建四个单独的块,link数组中的每个元素都与{{1}中的相应元素相关联数组?

但是,您实际上正在输出 16个块,link2link的每个组合一个。

而是尝试:

link1

答案 2 :(得分:2)

阅读你的问题,很难说出你真正想知道的是什么。我相信Sinan Unur是正确的,并且您希望在两个阵列上同时迭代。正如他所说,List :: MoreUtils提供了非常方便的each_array()函数。

通过索引迭代一个或多个数组也很简单。

您可以生成索引列表,以便与普通for循环一起使用。这使用$#来获取数组中最后一个值的索引。

for ( 0..$#array ) { ... }

或者您可以使用C风格的循环来生成索引。这使用了在标量上下文中计算的数组返回元素数的事实。

for ( my $i=0; $i<@array; $i++ ) { ... }

也可以使用$#

编写
for ( my $i=0; $i<=$#array; $i++ ) { ... }

阅读完代码后,很明显您不熟悉Perl's quoting operators。有效地使用它们可以使脚本更容易编写和阅读。

友好地请允许我整理你的剧本:

#!/usr/bin/perl

# Always:
use strict;
use warnings;

#my $TARGET_DIR  = 'D://projects//SW Model ODME';
my $TARGET_DIR  = '.';

my $TARGET_FILE = 'aptest.s';

# Using qw() makes long lists of 
# literals easier to type and read.
# Consider finding better names than link and link1.
# Something that describes the relationship between
# the two arrays.
my @link = qw(
    319-116264||319-118664
    320-116380||320-116846
    321-119118||321-119119
    322-115298||322-119087
);

my @link1 = qw(
    116264-319||118664-319
    116380-320||116846-320
    119118-321||119119-321
    115298-322||119087-322
);

# check the results of chdir.  
chdir($TARGET_DIR) 
    or die "Unable to enter $TARGET_DIR - $!\n";

# Use a lexical filehandle.
# Use 3 arg open
# Check the results of open - you need to know if it fails.
open (my $fsas, '>>', $TARGET_FILE)
    or die "Unable to open $TARGET_FILE - $!\n";

# Verify that the link arrays are both sized appropriately.
die "Link arrays are not the same size."
    unless @link == @link1;

# Loop over the indexes of the array.
# For very (very) large arrays it is 
# more efficient to use a C-style for loop:
#   for( my $i = 0; $i < @link; $i++ ) {
foreach my $i (0..$#link) {
    my $link  = $link[$i];
    my $link1 = $link1[$i];

    print $fsas Get_Link_Text($link, $link1);
}

# Broke out your formatting code into a routine for readability.
# Used a heredoc to make the formatting easier to read.
# Also, took advantage of variable interpolation in the heredoc to further
# improve readability.
# I preserved the whitespace at the end of lines, is it really necessary?
sub Get_Link_Text {
    my $link = shift;
    my $link1 = shift;

    return <<"--END_TEXT--"; 
RUN PGM=HWYLOAD 
MATI=daily_trucks.MAT  
NETI=FAF_Network_V11.net  
NETO=MiamiDade.NET 
PARAMETERS MAXITERS=1, GAP=0.001, COMBINE=EQUI  
FUNCTION {   
TC[1] = T0*(1+0.15*(V/100)^(4))}    
FUNCTION V = (VOL[1]) 
PHASE=ILOOP 
PATHLOAD PATH=TIME, MW[1]=MI.1.1, SELECTLINK=(Link=$link), VOL[2]=MW[1] 
PATHLOAD PATH=TIME, MW[2]=MI.1.1, SELECTLINK=(Link=$link1), VOL[3]=MW[2] 
ENDPHASE  
ENDRUN 


--END_TEXT--
}

答案 3 :(得分:0)

在重现错误的同时,您是否可以减小代码和示例数据的大小?我无法立即看到实际和预期产出之间的差异。

有时,找到导致问题的最小代码和数据集会使解决方案显而易见。

仔细一点,只有一位输出代码可变:

print FSAS "PATHLOAD PATH=TIME, MW[1]=MI.1.1, SELECTLINK=(Link=".$link."), VOL[2]=MW[1] \n";
print FSAS "PATHLOAD PATH=TIME, MW[2]=MI.1.1, SELECTLINK=(Link=".$link1."), VOL[3]=MW[2] \n";

你的错误可能就在那里。