Reputation:
I have these sets of arrays which has two elements for each.
@a = ("a", "b");
@i = (1, 2);
@s = ( "\\!", "\?");
How do I make the result such that it'll return
a1!, b2?
And I need them to be a new set of an array like
@new =(a1!,b2?)
I wrote the code for output of the answer
$i = length(@a);
for (0..$1) {
@array = push(@array, @a[$i], @s[$i];
}
print @array;
However, it only returned
syntax error at pra.pl line 10, near "];"
Thank you in advance.
Upvotes: 0
Views: 1062
Reputation: 66883
The basic idea you have is good, to iterate simultaneously using index of an array. But the code has many elementary errors and it also doesn't do what the examples show. I suggest to first make a thorough pass through a modern and reputable Perl tutorial.
The examples indicate that you want to concatenate (see .
operator) elements at each index
use warnings;
use strict;
use feature 'say';
my @a1 = ('a', 'b');
my @a2 = (1, 2);
my @a3 = ('!', '?');
my @res;
foreach my $i (0..$#a1) {
push @res, $a1[$i] . $a2[$i] . $a3[$i];
}
say for @res;
where $#a1
is the index of the last element of array @a1
. This assumes that all arrays are of the same size and that all their elements are defined.
This exact work can be done using map in one statement
my @res = map { $a1[$_] . $a2[$_] . $a3[$_] } 0..$#a1;
with the same, serious, assumptions. Even if you knew they held, do you know for sure, in every run on any data? For a robust approach see the answer by mwp.
There is also each_array from List::MoreUtils, providing a "simultaneous iterator" for all arrays
my $ea = each_array(@a1, @a2, @a3);
my @res;
while ( my ($e1, $e2, $e3) = $ea->() ) {
push @res, $e1 . $e2 . $e3
}
which is really useful for more complex processing.
A quick run through basics
Always have use warnings;
and use strict;
at the beginning of your programs. They will catch many errors that would otherwise take a lot of time and nerves.
Don't use single-letter variable names. We quickly forget what they meant and the code gets hard to follow, and they make it way too easy to make silly mistakes.
Array's size is not given by length
. It is normally obtained using context -- when an array is assigned to a scalar the number of its elements is returned. For iteration over indices there is $#ary
, the index of the last element of @ary
. Then the list of indices is 0 .. $#ary
, using the range (..
) operator
The sigil ($
, @
, %
) at the beginning of an identifier (variable name) indicates the type of the variable (scalar, array, hash). An array element is a scalar so it needs $
-- $ary[0]
The push doesn't return array elements but it rather adds to the array in its first argument the scalars in the list that follows.
The print @array;
prints array elements without anything between them. When you quote it spaces are added, print "@array\n";
. Note the handy feature say
though, which adds the new line.
Upvotes: 4
Reputation: 39158
use 5.008;
use List::AllUtils qw(zip_by);
⋮
my @new = zip_by { join '', @_ } \@a, \@i, \@s;
zip_by
is a subroutine from the List::AllUtils
module on CPAN. So it's not built-in.
use v6;
⋮
my @new = map { .join }, zip @a, @i, @s;
In Perl 6, zip
is already part of the standard library. This additionaly solution is here for flavour, it's an opportunity to show off strengths: does the same job, but with less syntax in comparison, and works out of the box.
v6
is not strictly necessary, here I just used it for contrast to indicate the version. But at the beginning of a file it also has the nice property that if you accidentally run Perl 6 code in Perl 5, you'll get a nice error message instead of a cryptic syntax error. Try it! From the use VERSION
documentation:
An exception is raised if VERSION is greater than the version of the current Perl
Upvotes: 4
Reputation: 1214
use warnings;
use strict;
use Data::Dumper;
my $result = [];
my @a = ("a", "b");
my @i = (1, 2);
my @s = ( "\!", "\?");
my $index = 0;
for my $a ( @a ) {
push( @$result, ($a[$index], $i[$index], $s[$index]) );
$index = $index + 1;
}
print Dumper(@$result);
Upvotes: -1
Reputation: 8467
use strict;
and use warnings;
(and use my
to declare variables).?
and !
in Perl strings, and you can use the qw//
quote-like operator to easily build lists of terms.length(@a)
to determine the last index, but Perl array indexes are zero-based, so the last index would actually be length(@a) - 1
. (But that's still not right. See the next point...) length
function is for strings.$i
, but then you reference the variable $1
on the next line. Those are two different variables.$_
).$a[$i]
, not @a[$i]
. Because you only want a single, scalar value, the expression has to start with the scalar sigil $
. (If instead you wanted a list of values from an expression, you would start the expression with the array sigil @
.)push
modifies the array given by the first argument, so there's no need to assign the result back to the array in the expression. push
expression.@new
and @array
, and you are only adding elements from @a
and @s
(i.e. you forgot about @i
).Here is a working version of your implementation:
use strict;
use warnings;
use List::Util qw{max};
my @a = ("a", "b");
my @i = ("1", "2");
my @s = ("!", "?");
my @array;
my $length = max scalar @a, scalar @i, scalar @s;
foreach my $i (0 .. $length - 1) {
push @array, ($a[$i] // '') . ($i[$i] // '') . ($s[$i] // '');
}
print @array;
(The //
means "defined-or".)
Here's how I might write it:
use strict;
use warnings;
use List::Util qw{max};
my @a = qw/a b/;
my @i = qw/1 2/;
my @s = qw/! ?/;
my @array = map {
join '', grep defined, $a[$_], $i[$_], $s[$_]
} 0 .. max $#a, $#i, $#s;
print "@array\n";
(The $#a
means "give me the index of the last element of the array @a
.")
Upvotes: 2