Reputation: 227
I have an array containing 10 numbers. I want to pick numbers in array index 0,2,4,6,8 and put them in a new array. Likewise with index 1,3,5,7,9. I am new to Perl (started a few days ago).
My program:
my @b;
@a = (1,2,3,4,5,6,7,8,9,10);
for($i=0;$i<=$#a;$i++)
{
push(@b,$a[$i+1]);
}
print "@b";
What am I doing wrong?
Upvotes: 0
Views: 2481
Reputation: 6378
List::MoreUtils
has an indexes
function:
use List::MoreUtils qw{indexes} ;
use 5.10.0 ;
my @a = (1,2,3,4,5,6,7,8,9,10) ;
# index of array where even
say foreach indexes { $_ % 2 == 0 } @a ;
# index of array where odd
say foreach indexes { $_ % 2 != 0 } @a ;
I admit this may be sort of inelegant and it's possibly cheating here to use a module - especially one that is not in CORE. It would be convenient if List::MoreUtils
and List::Utils
were just one CORE module, but still not as elegant as some the other answers here.
Upvotes: 1
Reputation: 107030
A few things:
use strict;
and use warnings;
. These will catch a lot of errors. If you use use strict;
, you'll have to declare your variables with my
(sometimes you'll use our
, but 99% of the time, you'll use my
)for
loop, you're using the default variable $_
. This variable is evil for a variety of reasons. (One, it's global in scope, so something else could change this variable on your and you wouldn't know.). Declare your variables except in situations where you must use $_
.{
on the line with the for
and while
. Another is to avoid the C style
for loop (and to avoid foreach
which is just an alias to for
)$i <= $#a
than $i<=$a
.Here's my interpretation of your program:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say); #A nicer 'print'
my @a = qw(12 13 14 15 16 17 18 19 20);
my @even;
my @odd;
for my $element (0..$#a) {
if ( $element % 2 ) {
push @odd, $a[$element];
}
else {
push @even, $a[$element];
}
}
say '@even = ' . join ': ', @even;
say '@odd = ' . join ': ', @odd;
The output:
@even = 12: 14: 16: 18: 20
@odd = 13: 15: 17: 19
for
loop. I use the 0..$#a
to go through each element of the array. The $#
is returns the last index of the array. Note that this is easier to understand than the for($i=0;$i<=$#a;$i++)
that you used. It's one of the reasons why C style for loops are discouraged.%
to parse my even/odd. Modulo is like remainder division. If the number is odd, the modulo % 2
will be a 1. Otherwise, it's zero. Modulo operations are great for anything that works on a cycle. But let's get back to your program. Here's your original code with a few minor tweaks.
use strict;
and use warnings;
. These catch about 99% of your programming errors.use feature qw(say);
because say
is nicer when it comes to debugging. I can take a statement, copy it, and then throw say qq(...);
around it and see what it's doing.say
statements to reveal the logic of your code. Let's watch what happens. Here's your program slightly modified:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
my @b;
my @a = (1,2,3,4,5,6,7,8,9,10);
my $i;
for($i=0; $i<=$#a; $i++) {
say "Index = $i Element = $a[$i + 1]";
say qq(push(\@b, $a[$i+1]););
push(@b,$a[$i+1]);
}
print "@b";
And here's the output:
Index = 0 Element = 2
push(@b, 2);
Index = 1 Element = 3
push(@b, 3);
Index = 2 Element = 4
push(@b, 4);
Index = 3 Element = 5
push(@b, 5);
Index = 4 Element = 6
push(@b, 6);
Index = 5 Element = 7
push(@b, 7);
Index = 6 Element = 8
push(@b, 8);
Index = 7 Element = 9
push(@b, 9);
Index = 8 Element = 10
push(@b, 10);
Use of uninitialized value in concatenation (.) or string at ./test.pl line 11.
Index = 9 Element =
Use of uninitialized value within @a in concatenation (.) or string at ./test.pl line 12.
push(@b, );
Use of uninitialized value $b[9] in join or string at ./test.pl line 15.
I can see the how each push
statement is being executed, and look at that, you're pushing in each and every element. Actually, you're not because you used $a[$i+1]
as what you're pushing.
Using use warnings
and I can see that I am trying to push the non-existant $a[10]
into your @b
array.
Let's change your for
loop to go to every other element
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
my @b;
my @a = qw(1 2 3 4 5 6 7 8 9 10);
my $i;
for ($i=0; $i <= $#a; $i += 2) {
push @b, $a[$i];
}
The first element is $a[0]
. The next element in the loop is $a[2]
because I added 2
to the index instead of just incrementing it by 1
. Now, I'll go through all the even elements and skip all of the odd elements.
And the output:
1 3 5 7 9
(Note that $a[0] = 1. That's why they're all odd numbers. It's why I started at 12
in my program, so $a[0] = 12 which is the even number).
My preference would be to use the while
and avoid the for(...; ...; ...)
construct:
#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
my @b;
my @a = qw(1 2 3 4 5 6 7 8 9 10);
my $i = 0;
while ( $i < $#a ) {
push @b, $a[$i];
$i += 2;
}
Upvotes: 1
Reputation: 70722
Simple.
my @a = (1,2,3,4,5,6,7,8,9,10);
my (@even, @odd);
for ( @a ) {
$_ % 2 ? push @odd, $_ : push @even, $_;
}
Upvotes: 2
Reputation: 50637
I suggest avoiding for
loop as it's easier to make mistake somewhere in its usage, and use foreach
my @a = (1,2,3,4,5,6,7,8,9,10);
my (@even, @odd);
foreach my $i (0 .. $#a) {
if ($i % 2) { push @odd, $a[$i] } else { push @even, $a[$i] }
}
You can also use map
to test array index modulo %
2, and then for @even
decide to filter it by ()
or take value for it using $a[$_]
my @even = map { $_%2 ? () : $a[$_] } 0 .. $#a;
my @odd = map { $_%2 ? $a[$_] : () } 0 .. $#a;
Upvotes: 2
Reputation: 780673
Even:
for($i=0;$i<=$#a;$i+=2)
{
push(@b,$a[$i]);
}
Odd:
for($i=1;$i<=$#a;$i+=2)
{
push(@b,$a[$i]);
}
Upvotes: 1