user9639111
user9639111

Reputation:

How to add each element of array to another array's each element?

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

Answers (4)

zdim
zdim

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

daxim
daxim

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

Justinus Hermawan
Justinus Hermawan

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

mwp
mwp

Reputation: 8467

  1. Always use strict; and use warnings; (and use my to declare variables).
  2. You don't need to escape ? and ! in Perl strings, and you can use the qw// quote-like operator to easily build lists of terms.
  3. You are using 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...)
  4. To get an array's length in Perl, you want to evaluate it in scalar context. The length function is for strings.
  5. You have not accounted for the situation when the arrays are not all the same length.
  6. You assign the last index to a variable $i, but then you reference the variable $1 on the next line. Those are two different variables.
  7. You are iterating from zero to the last index, but you aren't explicitly assigning the iterator to a variable, and you aren't using the implicit iterator variable ($_).
  8. To get a single array element by index in Perl, the syntax is $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 @.)
  9. 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.
  10. You are missing a closing parenthesis in your push expression.
  11. In your same code, you have @new and @array, and you are only adding elements from @a and @s (i.e. you forgot about @i).
  12. You are pushing elements onto the array, but you aren't concatenating them into the desired string format.

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

Related Questions