Re: List into two-dimensional array
by hippo (Bishop) on Dec 14, 2020 at 19:02 UTC
|
use strict;
use warnings;
use Test::More tests => 2;
use List::MoreUtils 'part';
my ($C, $R) = (4, 3);
my @list = 1..12;
my $i = 0;
my @AoA = part { int ($i++ / $C) } @list;
is_deeply \@AoA, [[1 .. 4], [5 .. 8], [9 .. 12]];
is_deeply \@list, [1..12];
| [reply] [Watch: Dir/Any] [d/l] |
|
use strict;
use warnings;
use Test::More tests => 2;
use List::MoreUtils 'natatime';
my ($C, $R) = (4, 3);
my @list = 1..12;
my @AoA;
my $iter = natatime($C, @list);
while ( my @chunk = $iter->() ) {
push @AoA, [@chunk];
}
is_deeply \@AoA, [[1 .. 4], [5 .. 8], [9 .. 12]];
is_deeply \@list, [1..12];
Updated: fixed two blunders in original post. Thanks LanX.
Update: This question reminds me of another recent node: How to Split on specific occurrence of a comma (where my response contains some CPAN List module refs)
| [reply] [Watch: Dir/Any] [d/l] |
|
Thanks to CPAN, most things devolve into "already-thoroughly-solved problems." MoreUtils is priceless.
| [reply] [Watch: Dir/Any] |
Re: List into two-dimensional array
by choroba (Cardinal) on Dec 14, 2020 at 19:14 UTC
|
In the spirit of TIMTOWTDI:
my @AoA;
for (0 .. $#list) {
push @AoA, [] if $_ % $C == 0;
push @{ $AoA[-1] }, $list[$_];
}
or, without using indices:
my @AoA = [];
for (@list) {
push @AoA, [] if $C == @{ $AoA[-1] };
push @{ $AoA[-1] }, $_;
}
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: List into two-dimensional array
by Cristoforo (Curate) on Dec 14, 2020 at 20:11 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw/ natatime /;
my @list = qw(1 2 3 4 5 6 7 8 9 10 11 12);
my @AoA;
my $it = natatime 4, @list;
while (my @vals = $it->()) {
push @AoA, \@vals;
}
print "@list\n";
use Data::Dumper;print Dumper \@AoA;
This would leave the original array unchanged.
Output:
1 2 3 4 5 6 7 8 9 10 11 12
$VAR1 = [
[
'1',
'2',
'3',
'4'
],
[
'5',
'6',
'7',
'8'
],
[
'9',
'10',
'11',
'12'
]
];
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: List into two-dimensional array
by haukex (Archbishop) on Dec 14, 2020 at 18:25 UTC
|
use warnings;
use strict;
use Test::More tests => 2;
my ($cols,$rows) = (4,3);
my @list = (1..12);
my @AoA = map { [ @list[ $_*$cols .. ($_+1)*$cols-1 ] ] } 0..$rows-1;
is_deeply \@AoA, [[1 .. 4], [5 .. 8], [9 .. 12]]
or diag explain \@AoA;
is_deeply \@list, [1..12];
TIMTOWTDI, plenty of other solutions are of course possible. Update: This one assumes that your list fits exactly into the rows and cols that you appear to know beforehand, at least based on your example code.
| [reply] [Watch: Dir/Any] [d/l] |
Re: List into two-dimensional array
by tybalt89 (Monsignor) on Dec 14, 2020 at 22:23 UTC
|
#!/usr/bin/perl
use strict; # https://perlmonks.org/?node_id=11125178
use warnings;
my @list = 1 .. 12;
my @AoA = [];
my $C = 4;
push @{ @{ $AoA[-1] } < $C ? $AoA[-1] : \@AoA },
@{ $AoA[-1] } < $C ? $_ : [ $_ ] for @list;
use Data::Dump 'dd'; dd \@list; dd \@AoA;
Outputs:
[1 .. 12]
[[1 .. 4], [5 .. 8], [9 .. 12]]
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: List into two-dimensional array
by ikegami (Patriarch) on Dec 14, 2020 at 18:43 UTC
|
sub group {
my $n = shift;
my @rv;
push @rv, [ splice(@_, 0, $n) ] while @_;
return @rv;
}
my @rv = group($C, @list);
Update: Woops! Fixed issue brought up by haukex in reply. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
sub group {
my $n = shift;
my @rv;
push @rv, splice(@_, 0, $n) while @_;
return @rv;
}
That just returns a copy of the original list. You probably meant push @rv, [ splice(@_, 0, $n) ] while @_;.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: List into two-dimensional array
by LanX (Saint) on Dec 14, 2020 at 21:15 UTC
|
> I'm seeking an equivalent without splice - so that @list remains unaffected. Any suggestions...?
If @list doesn't have millions of entries, I'd just copy to a new @tmp array before prior to using your solution.
But in the sense of TIMTOWTDI and with the power of autovivification ... :)
(demo in debugger)
DB<260> @a= "a" .. "h"
DB<261> @b=(); $i=0; $C=3
DB<262> push @{ $b[ $i++/$C ] } , $_ for @a
DB<263> x @b
0 ARRAY(0x3d7e3b0)
0 'a'
1 'b'
2 'c'
1 ARRAY(0x3d81440)
0 'd'
1 'e'
2 'f'
2 ARRAY(0x3d8e7f8)
0 'g'
1 'h'
DB<264> x @a
0 'a'
1 'b'
2 'c'
3 'd'
4 'e'
5 'f'
6 'g'
7 'h'
DB<265>
HTH :)
NB: you haven't been clear about your row $R requirement.
update
it's a poor man's solution for hippo's part() solution in Re: List into two-dimensional array, but since List::MoreUtils isn't core and List::Util doesn't offer it ...
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: List into two-dimensional array
by johngg (Canon) on Dec 15, 2020 at 11:18 UTC
|
johngg@abouriou:~$ perl -Mstrict -Mwarnings -MData::Dumper -E '
my @list = qw{ 1 2 3 4 5 6 7 8 9 10 11 12 };
my( $nCols, $nRows ) = ( 4, 3 );
my @AoA = sub {
my @tAoA;
push @tAoA, [ splice @_, 0, $nCols ]
while @_;
return @tAoA;
}->( @list );
print Data::Dumper->Dumpxs( [ \ @list, \ @AoA ], [ qw{ *list *AoA } ]
+);'
@list = (
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12'
);
@AoA = (
[
'1',
'2',
'3',
'4'
],
[
'5',
'6',
'7',
'8'
],
[
'9',
'10',
'11',
'12'
]
);
I hope this is of interest.
| [reply] [Watch: Dir/Any] [d/l] |
Re: List into two-dimensional array
by kcott (Archbishop) on Dec 16, 2020 at 22:37 UTC
|
On the basis of what you've provided, you can just use this for loop instead of your current while loop:
for (my $i = 0; $i <= $#list; $i += $C) {
push @AoA, [ @list[$i .. $i + $C - 1] ];
}
Output (showing "@list remains unaffected"):
[[1 .. 4], [5 .. 8], [9 .. 12]]
[1 .. 12]
I don't know why you've declared and initialised $R but then didn't use it.
It's complete guesswork on my part, but I get the impression you're using a matrix with all elements being used.
If that's the case, the code above works if you add a couple of elements to @list; giving this output:
[[1 .. 4], [5 .. 8], [9 .. 12], [13, 14, undef, undef]]
[1 .. 14]
Here, all rows of @AoA have the same number of elements.
If my guess was wrong, and that's not what you want, use this code:
for (my $i = 0; $i <= $#list; $i += $C) {
my $end = $i + $C - 1;
$end = $#list if $end > $#list;
push @AoA, [ @list[$i .. $end] ];
}
To get this output:
[[1 .. 4], [5 .. 8], [9 .. 12], [13, 14]]
[1 .. 14]
Here, all rows of @AoA do not have the same number of elements.
With the original @list (holding 12 elements), this code produces the same output as the first code I posted:
[[1 .. 4], [5 .. 8], [9 .. 12]]
[1 .. 12]
| [reply] [Watch: Dir/Any] [d/l] [select] |