JQKP
JQKP

Reputation: 75

Joining an array of arrays

I have an array @ary of unknown size. Each element, $ary[$i], is an arrayref of unknown size. Each element of that, $ary[$i][$j], is a string.

I wish to concatenate all of the $ary[0][$j] with all of the $ary[1][$j] with all of the… and so on.

That is, suppose my array looks like this:

$ary[0] = ['foo', 'fun'];
$ary[1] = ['bar', 'bun', 'blip'];
$ary[2] = ['baz', 'zun'];

Then I'd want the return to be:

(
'foo bar baz',
'foo bar zun',
'foo bun baz',
'foo bun zun',
'foo blip baz',
'foo blip zun',
'fun bar baz',
'fun bar zun',
'fun bun baz',
'fun bun zun',
'fun blip baz',
'fun blip zun'
)

(Alternatively, the return could be an array of arrayrefs: (['foo', 'bar', 'baz'], ['foo', 'bar', 'zun'], …).)

How can I do this?

Upvotes: 1

Views: 344

Answers (2)

JQKP
JQKP

Reputation: 75

I did this and it worked:

#!/usr/bin/perl
use strict;
use warnings;

my @arry= ();
$arry[0] = ['foo', 'fun'];
$arry[1] = ['bar', 'bun', 'blip'];
$arry[2] = ['baz', 'zun'];

my @combos = ();
$combos[0] = [''];

for my $i (1 .. @arry) {
  for my $j (0 .. @{$combos[$i - 1]} - 1) {
    push @{$combos[$i]}, "$combos[$i - 1][$j] $_" for @{$arry[$i - 1]};
  }
}
my @goodcombos = @{$combos[-1]};
s/^ // for @goodcombos;
print "$_\n" for @goodcombos;

It builds up the required concatenations, storing the first terms in $combos[1], the concatenations of the first 2 terms in $combos[2], the concatenations of the first 3 terms in $combos[3], and so on.

Upvotes: 1

Miller
Miller

Reputation: 35198

I would suggest starting with an array of indexes, and then iterate through all combinations:

#!/usr/bin/env perl

use strict;
use warnings;
use feature qw(say);

my @array = (
    [qw(foo fun)],
    [qw(bar bun blip)],
    [qw(baz zun)],
);

my @index = (0) x @array;

SET:
while (1) {
    my @set = map { $array[$_][ $index[$_] ] } (0 .. $#index);

    say "@set";

    $index[-1]++;

    for my $i (reverse 0 .. $#index) {
        if ($index[$i] > $#{ $array[$i] }) {
            $index[$i] = 0;
            if ($i > 0) {
                $index[$i - 1]++;
            } else {
                last SET;
            }
        }
    }
}

Results:

foo bar baz
foo bar zun
foo bun baz
foo bun zun
foo blip baz
foo blip zun
fun bar baz
fun bar zun
fun bun baz
fun bun zun
fun blip baz
fun blip zun

There are cpan modules to do this type of combination, but don't know them off hand.

Upvotes: 3

Related Questions