I have 2 empty arrays that I add items to using a for loop.
@main = (
"a 1 b 2 c 3 ",
"d 4",
"e 5 f 6 g 7 h 8",
"i 9 j 10",
);
@arr1 = (); #only gets the letters
#supposed to look like:
#(
#[a,b,c]
#[d]
#[e,f,g,h]
#[i,j]
#)
@arr2 = (); #only gets the numbers
#supposed to look like:
#(
#[1,2,3]
#[4]
#[5,6,7,8]
#[9,10]
#)
for($i=0;@main;$i =1){
@line = split(/\s /,shift(@main));
push(@arr1,[]);
push(@arr2,[]);
while(@line){
push(@arr1[$i],shift(@line));
push(@arr2[$i],shift(@line));
}
}
error:
Experimental push on scalar is now forbidden at index.pl line 29, near "))"
Experimental push on scalar is now forbidden at index.pl line 30, near "))"
It seems that @arr[$i] returns a reference to an array. How do I get this array and add items to it?
CodePudding user response:
The first argument of push must be an array, not an array slice. I think you wanted @{ $arr1[$i] } (but that's not your only problem). Make sure that you're using use strict; use warnings;! –ikegami
for(my $i=0;@main;$i =1){
my @line = split(/\s /,shift(@main));
push(@arr1,[]);
push(@arr2,[]);
while(@line){
# ↓↓ ↓
push( @{ $arr1[$i] } ,shift(@line));
push( @{ $arr2[$i] } ,shift(@line));
}
}
Not exactly sure how it works, probably turns the reference into an actual array of something along those lines.
Another solution I came up with myself, which adds the finished array after instead of adding values slowly:
for($i=0;@main;$i =1){
@line = split(/\s /,shift(@main));
@subArr1 = ();
@subArr2 = ();
while(@line){
push(@subArr1,shift(@line));
push(@subArr2,shift(@line));
}
push(@arr1,[@subArr1]);
push(@arr2,[@subArr2]);
}
CodePudding user response:
As of perl 5.36, you can iterate over multiple elements of a list at once in a foreach
loop, which lets you clean this up a bit:
#!/usr/bin/env perl
use 5.036;
# The next two lines aren't strictly needed because of the above, but
# I like to be explicit
use strict;
use warnings;
use experimental qw/for_list/;
use Data::Dumper;
my @main = (
"a 1 b 2 c 3 ",
"d 4",
"e 5 f 6 g 7 h 8",
"i 9 j 10",
);
my (@arr1, @arr2);
for my $line (@main) {
my (@sub1, @sub2);
for my ($name, $num) (split " ", $line) {
push @sub1, $name;
push @sub2, $num;
}
push @arr1, \@sub1;
push @arr2, \@sub2;
}
print Dumper(\@arr1, \@arr2);
You can use the same approach in older versions using natatime
from the List::MoreUtils
module (Available from CPAN or your OS's package manager):
#!/usr/bin/env perl
use strict;
use warnings;
use List::MoreUtils qw/natatime/;
use Data::Dumper;
my @main = (
"a 1 b 2 c 3 ",
"d 4",
"e 5 f 6 g 7 h 8",
"i 9 j 10",
);
my (@arr1, @arr2);
for my $line (@main) {
my (@sub1, @sub2);
my $it = natatime 2, split(" ", $line);
while (my ($name, $num) = $it->()) {
push @sub1, $name;
push @sub2, $num;
}
push @arr1, \@sub1;
push @arr2, \@sub2;
}
print Dumper(\@arr1, \@arr2);
The thing these have in common is building up each subarray first, and then pushing references to them onto @arr1
and @arr2
at the end, removing the need for a lot of the arrayref dereferencing syntax. They also iterate directly over the elements you're storing in the subarrays instead of modifying the source directly with shift
.
CodePudding user response:
Please inspect the following demonstration code for a compliance with your problem.
The code is based upon comments in OP's code with description what result arrays should look alike.
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my(@main,@arr1,@arr2);
@main = (
"a 1 b 2 c 3 ",
"d 4",
"e 5 f 6 g 7 h 8",
"i 9 j 10",
);
for ( @main ) {
push(@arr1,[ /(\d )/g ]);
push(@arr2,[ /([a-z])/g ]);
}
say Dumper(\@arr1,\@arr2);
Output
$VAR1 = [
[
'1',
'2',
'3'
],
[
'4'
],
[
'5',
'6',
'7',
'8'
],
[
'9',
'10'
]
];
$VAR1 = [
[
'a',
'b',
'c'
],
[
'd'
],
[
'e',
'f',
'g',
'h'
],
[
'i',
'j'
]
];