16

Suppose I have 2 arrays like mentioned below

@a1 = ("Vinay", Raj, harry);
@b1 = ("dude","rock");

After merging I want to have result like this

[
    Vinay
    dude
    Vinay
    rock
    Raj
    dude
    Raj
    rock
    harry
    dude
    harry
    rock
]

basically I want to merge the each index values of array1 to all the index values of array2.

Adding to the above question I have another query.

For the same question above how to merge 2 arrays at particular array index. For example I have 2 arrays of each 160 elements, now I want to merge array at every 5th element in sets, is that possible?

serenesat
  • 4,611
  • 10
  • 37
  • 53
Vinay D
  • 273
  • 2
  • 4
  • 11
  • 4
    Please post minimal working examples and what you've tried in the future. Additionally, always, always, **always** put `use strict; use warnings;` at the top of your Perl files. You shouldn't use barewords when you want a string! – jmdeldin Oct 28 '12 at 06:43
  • 4
    This is not a merge, this is a cartesian product. – Steven Lu Aug 29 '13 at 19:00

6 Answers6

53

Just make a new array:

my @merged = (@a1, @b1);

Here's a complete example:

my @a1 = ("foo", "bar");
my @a2 = ("baz", "spam");

my @merged = (@a1, @a2);

print $merged[3]; #=> "spam"

EDIT: I missed the ordering requirement. You just need to zip them together, which you can do with List::MoreUtils:

use List::MoreUtils qw(zip);
use Data::Dumper qw(Dumper);

my @a1 = ("Vinay", "Raj", "harry");
my @a2 = ("dude", "rock");

my @merged = zip(@a1, @a2);

print Dumper(\@merged);
jmdeldin
  • 5,354
  • 1
  • 28
  • 21
  • This is the standard way to do array concatenation in Perl, but I don't think that's what this question is asking. – mattc Oct 28 '12 at 06:37
  • @mattc: Thanks -- I realized that after posting. Updated with a `zip` example. – jmdeldin Oct 28 '12 at 06:41
  • +1 Forgot about `zip`. I knew there was a better way to do it than with nested for loops. – mattc Oct 28 '12 at 06:45
  • 1
    -1. Why all the upvotes for a wrong answer? Neither of the pieces of posted code accomplish what the questioner asked for. – David Hammen Oct 28 '12 at 12:49
  • @DavidHammen: The upvotes probably occurred when the question was poorly formatted (hence my incorrect answer). Obviously, two maps should be used instead of `zip`, e.g., `map { my $x = $_; map { ($x, $_) } @b1 } @a1`. – jmdeldin Oct 28 '12 at 17:52
10

Here is one way to do it. May not be the best perl syntax, though. The double for loop means you will be pushing every combination of the two arrays into the merged array. I've tried to set it up so that the result is in the order you specified in the question.

my @merged;

for my $a ( @a1 ) {
  for my $b ( @b1 ) {
    push( @merged, ($a, $b) );
  }
}
mattc
  • 485
  • 3
  • 9
  • 4
    In general, please try to avoid the variables `$a` and `$b` as they have a very special meaning in the built-in [`sort`](http://p3rl.org/sort). Good answer though. :) – memowe Oct 28 '12 at 12:40
  • this is not working for me...:(, after merge i am seeing many repetations, as separate perl code the above logic works, but when i try to include in my main program its not working – Vinay D Oct 28 '12 at 21:00
  • 1
    @VinayD if you can edit the question to include actual code, we might be able to track down what the issue is. – mattc Oct 29 '12 at 04:04
  • hi for the same question above how to merge 2 arrays at particular array index, for example i have 2 arrays of each 160 elements , now i want to merge array at every 5th element in sets, is that possible..? – Vinay D Oct 29 '13 at 10:52
4

Here's another option:

use strict;
use warnings;
use Data::Dumper;

my $a = join ',', qw/Vinay Raj harry/;
my $b = join ',', qw/dude rock/;

my @merged = map { split '-' } glob "{$a}-{$b}";

print Dumper \@merged;

Output:

$VAR1 = [
          'Vinay',
          'dude',
          'Vinay',
          'rock',
          'Raj',
          'dude',
          'Raj',
          'rock',
          'harry',
          'dude',
          'harry',
          'rock'
        ]
Kenosis
  • 6,196
  • 1
  • 16
  • 16
4

First off, don't use barewords, and as noted in jmdeldin's comment, always place use strict; use warnings; at the start of a script.

So how to make those lists @a1 and @b1? Either use quotes:

my @a1 = ('Vinay', 'Raj', 'harry');
my @a2 = ('dude', 'rock');

Or use qw:

my @a1 = qw(Vinay Raj harry);
my @a2 = qw(dude rock);

How to "merge" these as specified? One way is to use a pair of nested loops. Much more succinctly, use a map of a map:

my @merged = map {my $outer = $_; map {($outer, $_)} @b1} @a1;

You don't need any special capabilities from perl 5.12. Just take advantage of the fact that lists collapse.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
1

It could be done atrociously in one line:

@merged = grep {not ref} map {[our $t = $_], map {$t,$_} @b1} @a1;

and a bit less atrociously with a push inside

map {our $t = $_, map {push(@merged, $t, $_)} @b1} @a1;
Basil
  • 981
  • 1
  • 8
  • 20
  • 2
    Or even more simply, `@merged = map {my $outer = $_; map {($outer, $_)} @b1} @a1;` You don't need the `grep` or the `push`. Lists collapse. And it's best to prefer `my` over `our` except when you really need `our`. – David Hammen Oct 28 '12 at 12:57
0

Use Set::CrossProduct from CPAN.

The zip from List::MoreUtils zips elements at corresponding (and not cross) indices of its argument lists.

vapace
  • 340
  • 3
  • 9