oysterperl has asked for the wisdom of the Perl Monks concerning the following question:
Hi,
I have three arrays with elements shown below:
array1 = 1,2,3
array2 = a,b,c,d,e,f,g
array3 = I,II,III
I want it displayed like this:
1,a,I
2,a,I
3,a,I
4,a,I
5,a,I
1,a,II
2,a,II
3,a,II
4,a,II
5,a,II
1,a,III
2,a,III
3,a,III
4,a,III
5,a,III
1,b,I
2,b,I
3,b,I
4,b,I
5,b,I
1,b,II
2,b,II
3,b,II
4,b,II
5,b,II
1,b,III
2,b,III
3,b,III
4,b,III
5,b,III
and so on.
I am trying the following but its not able to loop correctly.
my $i = $j = $k = 0;
for my $i (@array1) {
for my $j (@array2) {
for my $k (@array3) {
print "$array1[k],$array2[j],$array3[i],\n";
$k++;
}
$j++;
}
$k++;
}
How can I fix this? Thanks in advance for your help.
Re: Printing from three arrays
by hippo (Bishop) on Sep 26, 2019 at 08:49 UTC
|
If you aren't doing anything else with them, just loop over the elements themselves instead of the indices. The innermost loop will loop most quickly, of course. So:
#!/usr/bin/env perl
use strict;
use warnings;
my @array1 = (1, 2, 3);
my @array2 = (qw/a b c/); # Enough to test
my @array3 = (qw/I II III/);
for my $alpha (@array2) {
for my $roman (@array3) {
for my $arabic (@array1) {
print "$arabic,$alpha,$roman\n";
}
}
}
| [reply] [d/l] |
|
Nested loops become unwieldy when you have many arrays. With a suitable module it does not matter how many dimension the input has:
use 5.010;
use Set::Scalar qw();
my $iter = Set::Scalar->cartesian_product_iterator(
map { Set::Scalar->new(@$_) }
[1, 2, 3],
[qw/a b c/],
[qw/I II III/],
);
while (my @m = $iter->()) {
say "@m";
}
There are numerous alternatives: https://metacpan.org/search?q=cartesian+product
Bonus:
use v6;
.say for cross (1, 2, 3), <a b c>, <I II III>
| [reply] [d/l] [select] |
Re: Printing from three arrays
by Discipulus (Canon) on Sep 26, 2019 at 08:55 UTC
|
use strict;
use warnings;
my @array1 = (1..5);
my @array2 = ('a','b','c','d','e','f','g');
my @array3 = ('I', 'II', 'III');
foreach my $letter(@array2){
foreach my $index_roman(0..$#array3){
foreach my $index (0..$#array1){
print "$array1[$index],$letter,$array3[$index_roman]\n";
}
}
}
PS as wisely said by hippo, cycling indexes is no more needed, so semplified nested loop will be:
foreach my $letter(@array2){
foreach my $roman(@array3){
foreach my $number (@array1){
print "$number,$letter,$roman\n";
}
}
}
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
Re: Printing from three arrays
by johngg (Canon) on Sep 26, 2019 at 14:29 UTC
|
johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E '
my @arr1 = qw{ 1 2 3 };
my @arr2 = q{a} .. q{g};
my @arr3 = qw{ I II III };
my $globStr
= qq{{@{ [ join q{,}, @arr1 ] }}}
. qq{{@{ [ join q{,}, @arr2 ] }}}
. qq{{@{ [ join q{,}, @arr3 ] }}};
say $globStr;
say for glob $globStr;'
{1,2,3}{a,b,c,d,e,f,g}{I,II,III}
1aI
1aII
1aIII
1bI
1bII
1bIII
1cI
1cII
1cIII
1dI
1dII
1dIII
1eI
1eII
1eIII
1fI
1fII
1fIII
1gI
1gII
1gIII
2aI
2aII
2aIII
2bI
2bII
2bIII
2cI
2cII
2cIII
2dI
2dII
2dIII
2eI
2eII
2eIII
2fI
2fII
2fIII
2gI
2gII
2gIII
3aI
3aII
3aIII
3bI
3bII
3bIII
3cI
3cII
3cIII
3dI
3dII
3dIII
3eI
3eII
3eIII
3fI
3fII
3fIII
3gI
3gII
3gIII
I hope this is of interest.
Update : AnomalousMonk quite rightly points out that I'm the idiot who didn't read the question properly, a failing that has dogged me since O- and A-levels at school :-(
Getting the left-hand value to circulate the fastest and inserting the required commas involves some jiggery-pokery to insert marker text into a re-ordered $globStr and a split, reverse and join in a map for each string generated by glob. Probably more trouble than it's worth.
johngg@shiraz:~/perl/Monks$ perl -Mstrict -Mwarnings -E '
my @arr1 = qw{ 1 2 3 };
my @arr2 = q{a} .. q{g};
my @arr3 = qw{ I II III };
my $globStr
= qq{{@{ [ join q{,}, @arr3 ] }}}
. q{__}
. qq{{@{ [ join q{,}, @arr2 ] }}}
. q{__}
. qq{{@{ [ join q{,}, @arr1 ] }}};
say $globStr;
say for
map { join q{,}, reverse split m{__} }
glob $globStr;'
{I,II,III}__{a,b,c,d,e,f,g}__{1,2,3}
1,a,I
2,a,I
3,a,I
1,b,I
2,b,I
3,b,I
1,c,I
2,c,I
3,c,I
1,d,I
2,d,I
3,d,I
1,e,I
2,e,I
3,e,I
1,f,I
2,f,I
3,f,I
1,g,I
2,g,I
3,g,I
1,a,II
2,a,II
3,a,II
1,b,II
2,b,II
3,b,II
1,c,II
2,c,II
3,c,II
1,d,II
2,d,II
3,d,II
1,e,II
2,e,II
3,e,II
1,f,II
2,f,II
3,f,II
1,g,II
2,g,II
3,g,II
1,a,III
2,a,III
3,a,III
1,b,III
2,b,III
3,b,III
1,c,III
2,c,III
3,c,III
1,d,III
2,d,III
3,d,III
1,e,III
2,e,III
3,e,III
1,f,III
2,f,III
3,f,III
1,g,III
2,g,III
3,g,III
| [reply] [d/l] [select] |
|
IIRC, glob iterates most slowly over its first (leftmost) iteration group, {1,2,3} in this case, and more rapidly over each succeeding iteration group, so that the the last (rightmost) group {I,II,III} iterates most quickly. This is the behavior I see in the output of your example code: the first (leftmost, arabic-number) field or column of each "1aI" output record/string changes most slowly, the second (middle, alpha) changes more quickly, and the third (rightmost, roman-number) column changes fastest.
However, oysterperl, as shown in the example of desired output in the OP, seems to want the first (leftmost, arabic-number) column to change most quickly, the second (alpha) column to change most slowly, and the third (roman-number) column to change at an intermediate rate. Is it possible to produce this result with a glob solution? (The OPed example output also has commas separating the columns, but this is easily done with a glob template.)
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
|
I checked the glob page, and I could not find something that would make it change it's ways, so you would need to split and join it :(
perl -e '@_=split(/=/, $_) and print join(", " ,@_[2,0,1]),"\n" for glob "{a,b,c}={I,II,III}={1,2,3,4}"'
it's cumbersome, though. I tried something with unshift pop but it was longer.
perl -E '@_=split /=/ and unshift(@_,pop @_) and say join ", ", @_ for glob "{a,b,c}={I,II,III}={1,2,3,4}"'
perl -E '@_=split /=/ and say join ", ", unshift(@_, pop @_) && @_ for glob "{a,b,c}={I,II,III}={1,2,3,4}"'
| [reply] [d/l] [select] |
|
Re: Printing from three arrays
by BillKSmith (Monsignor) on Sep 26, 2019 at 22:47 UTC
|
You should start every perl program with:
use strict;
use warnings;
The purpose is to help you solve you own problems. In this case, you will get several error messages. Some of them will not make any sense to you. Fix the easy ones and try again. You probably have fixed more than you thought. You may have also revealed a few more errors. Keep fixing errors a few at a time until it runs. If you really get stuck, ask for explanation of your remaining errors. Your current script probably will not run correctly even when it does run. You may have to ask for help again. It is much easier for the monks to find a fix you logic errors when they are not masked by other errors.
Another hint is to use meaningful variable names. Note the improvement in this solution.
use strict;
use warnings;
my @digits = qw(1 2 3);
my @letters = qw(a b c d e f g);
my @romans = qw(I II III);
foreach my $letter (@letters) {
foreach my $roman (@romans) {
foreach my $digit (@digits) {
print "$digit,$letter,$roman\n";
}
}
}
| [reply] [d/l] [select] |
Re: Printing from three arrays
by FreeBeerReekingMonk (Deacon) on Sep 26, 2019 at 21:06 UTC
|
edit:Deleted code that was identical to Discipulus's code.
You want to loop over the array index, you need to enumerate from 0 to the array length minus 1, which is that "$#".
The initialization (my $i = $j = $k = 0;) is not required because you already use the "my" in each loop.
A more C stylish approach (not necessarily better):
#!/usr/bin/env perl
use strict;
use warnings;
my @array1 = (1, 2, 3); #veryfast
my @array2 = (qw/a b c/); # Enough to test #veryslow
my @array3 = (qw/I II III/);
# my $i = $j = $k = 0;
for(my $i=0;$i<=$#array2;$i++) {
for(my $j=0;$j<=$#array3;$j++) {
for(my $k=0;$k<=$#array1;$k++) {
print "$array1[$k],$array2[$i],$array3[$j],\n";
}
}
}
Note that because in each iteration it needs to calculate $# these loops are slower than iterating over the values of each array, as already shown by other monks. | [reply] [d/l] |
Re: Printing from three arrays
by oysterperl (Novice) on Sep 30, 2019 at 06:52 UTC
|
Thank you, all. This worked like a charm. Very useful and informative discussion as well. Appreciate your help! | [reply] |
|
|