1

I want to create an array of arrays from a list of objects. but how to reset the array variable (@row and reuse it to hold items in the next sections)? I know the @row is declared once, when it is pushed into the array, emptying it will empty the @arrays too. How can I reset @row while not empty @arrays?

 use Data::Dumper;

    # sample data, could be a long list for complex data types
    my @list = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20);

    my @arrays;
    my @row;
    my $numSub = 10;

    foreach my $itm (@$list)  {
       if (scalar(@row) == $numSub) 
       {   
          push @arrays, \@row;
          @row = (); # clear array, cleared the array of arrays
          push @row, $itm;
        }
        else {
          push @row, $itm;
       }
   }
   # push the last reminder
    push @arrays, \@row;

   Dumper @arrays; # nothing 
1
  • I expect @arrays has two arrays with (1, , 10) and (11,, 20). Commented Mar 10, 2014 at 3:29

3 Answers 3

1

Put my @row inside of your foreach loop instead of outside. Then it will be a distinct variable every time through the loop.

Incidentally, there are nicer ways to write this, for example:

my @copy = @list;
while (@copy) {
  push @arrays, [ splice @copy, 0, $numSub ];
}

or

use List::Util 'max';
for (my $i = 0 ; $i < @list ; $i += $numSub) {
  push @arrays, [ @list[ $i .. max($i + $numSub, $#list) ] ];
}

or

use List::MoreUtils 'natatime';
my $iter = natatime $numSub, @list;
while (my @vals = $iter->()) {
  push @arrays, \@vals;
}
Sign up to request clarification or add additional context in comments.

1 Comment

If you put my @row inside the loop then it will only ever contain one element.
1

Create a new anonymous array instead of just taking a reference, or all your elements of @arrays will point to the same array ref.

push @arrays, [@row];

Also, if you're goal is just to build groups of 10 or less, then you can use the below method instead:

while (@list) {
    push @array, [splice @list, 0, 10];
}

Comments

0

There are a few problems with your code as it stands that prevent it from working in the first place.

  • You must always use strict and use warnings at the start of every Perl program. This would have alerted you to the second problem

  • You are looping over @$list, which would be fine if $list was an array reference, but the data you have defined is in @list and you need to use that

  • The Dumper function just returns a formatted string. At present you are just discarding it. To see it you need to use print Dumper \@arrays

  • As it stands, @arrays contains multiple references to the same array. You must copy @row to a new temporary array each time it is added to the list. The simplest way to do this is just push @arrays, [ @row ]

This program does what you require.

use strict;
use warnings;

use Data::Dumper;

my @list = 1 .. 20;

my @arrays;
my @row;
my $numSub = 10;

for my $itm (@list) {
  if (@row == $numSub) {
    push @arrays, [@row];
    @row = ();
  }
  push @row, $itm;
}

push @arrays, [@row];

print Dumper \@arrays;

output

$VAR1 = [
          [
            1,
            2,
            3,
            4,
            5,
            6,
            7,
            8,
            9,
            10
          ],
          [
            11,
            12,
            13,
            14,
            15,
            16,
            17,
            18,
            19
          ]
        ];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.