http://www.perlmonks.org?node_id=486914

holli has asked for the wisdom of the Perl Monks concerning the following question:

Brethren,

Normally I would try to figure this out, but I'm in a hurry so burdened with work atm. (one big project with a impossible deadline, 2 "can you please tweak that script to do x instead of y, can't be much" (but is), and i'm in charge to do the hardware operators work as long he is in holliday (which means running around cleaning printers ans stuff) And so i have to ask for assistance.

I have data in a table that looks like this:

1. digit
1Darth Vader
3Luke Skywalker
5Obi Wan Kenobi
2. digit
0Lighsabre
5Blaster
9Rocket launcher
3./4. digit
10Dagobah
14Kashyyyk


what boils down to this data structure.
@data = ( [ [1, "Darth Vader"], [3, "Luke Skywalker"], [5, "Obi Wan Kenobi"], ],[ [0, "Lighsabre "], [5, "Blaster"], [9, "Rocket launcher"], ],[ [10, "Dagobah"], [14, "Kashyyyk"], ], );
Now I need to shuffle this until I get the data in the form:
1010\tDarth Vader, Lightsabre, Dagobah 1510\tDarth Vader, Blaster, Dagobah .... 5914\tObi Wan Kenobi, Rocket Launcher, Kashyyyk
So I can put that stuff into two fields of a database.
__END__


holli, /regexed monk/

Replies are listed 'Best First'.
Re: All Combinations of three arrays.
by fizbin (Chaplain) on Aug 26, 2005 at 16:54 UTC
    I haven't bought Higher Order Perl yet, but I've looked at the code examples and have been inspired. With that in mind:
    # combines two pairs into a longer pair sub combine_codes_and_descriptions { my ($sofar, $next) = @_; if (!defined($sofar)) {return $next;} [$sofar->[0] . $next->[0], $sofar->[1] . ", " . $next->[1]]; } sub multi_dim_reduce { # $sofar optional my ($actionsub, $AoA, $combinesub, $sofar) = @_; if (@$AoA) { my $this_array = shift @$AoA; for my $elem (@$this_array) { my $subarray = [ @$AoA ]; multi_dim_reduce($actionsub, $subarray, $combinesub, $combinesub->($sofar,$elem)); } } else { $actionsub->($sofar); } } # The main event @data = ( [ [1, "Darth Vader"], [3, "Luke Skywalker"], [5, "Obi Wan Kenobi"], ],[ [0, "Lighsabre"], [5, "Blaster"], [9, "Rocket launcher"], ],[ [10, "Dagobah"], [14, "Kashyyyk"], ], ); multi_dim_reduce(sub {my ($c,$d) = @{$_[0]}; print "$c\t$d\n";}, [ @data ], \&combine_codes_and_descriptions);
    -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/; map{y/X_/\n /;print}map{pop@$_}@/for@/
Re: All Combinations of three arrays.
by saberworks (Curate) on Aug 26, 2005 at 18:35 UTC
    I asked a very similar question in the past, check it out: Conglomerate of arrays with no duplicates There were two modules posted in the comments there that do this exact thing. And they can do a recursive solution, so you can have an arbitrary number of sets.
Re: All Combinations of three arrays.
by halley (Prior) on Aug 26, 2005 at 16:40 UTC
    Normally I would try to figure this out, but I'm in a hurry and so i have to ask for assistance.

    You're a long-standing monk here; is this the attitude that you like to find at the front gate every day? It probably took you more time to type up your example than it would to code the solution.

    For the fixed-number-of-columns case, just nest loops.

    my $struct = [ [], [], [] ]; for my $A (@{$struct->[0]}) { for my $B (@{$struct->[1]}) { for my $C (@{$struct->[2]}) { ... } } }

    For the variable-number-of-columns case, a recursive solution or a stack iteration would work.

    --
    [ e d @ h a l l e y . c c ]

Re: All Combinations of three arrays.
by QM (Parson) on Aug 26, 2005 at 20:27 UTC
    Since we're being facetious, here's my replacement for loops. (If Perl could evaluate $data[$i][0..$#{$data[$i]}][$j] I wouldn't need the for loops at all.)
    #!/your/perl/here use strict; use warnings; # backwhack whitespace my @data = ( [ [1, 'Darth\ Vader'], [3, 'Luke\ Skywalker'], [5, 'Obi\ Wan\ Kenobi'], ],[ # note stray trailing blank here [0, 'Lighsabre\ '], [5, 'Blaster'], [9, 'Rocket\ launcher'], ],[ [10, 'Dagobah'], [14, 'Kashyyyk'], ], ); # transpose innermost 2D matrices my @new_data; foreach my $set ( 0..$#data ) { foreach my $pairs ( 0..$#{$data[$set]} ) { foreach my $items ( 0..$#{$data[$set][$pairs]} ) { $new_data[$set][$items][$pairs] = $data[$set][$pairs][$ite +ms]; } } } # comma-separated pattern specs for glob $"=','; # had to break this in two because of tab and newline issues my $glob1 = "{@{$new_data[0][0]}}{@{$new_data[1][0]}}{@{$new_data[2][0 +]}}"; my $glob2 = "{@{$new_data[0][1]}}" . '\,\ ' . "{@{$new_data[1][1]}}" . + '\,\ ' . "{@{$new_data[2][1]}}"; my @glob1 = glob $glob1; my @glob2 = glob $glob2; print map {"$glob1[$_]\t$glob2[$_]\n"} 0..$#glob1;

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Re: All Combinations of three arrays. (Algorithm::Loops)
by tye (Sage) on Aug 27, 2005 at 17:22 UTC

    Simple use of Algorithm::Loops, but so simple I didn't test it. (:

    #!/usr/bin/perl -w use strict; use Algorithm::Loops qw( NestedLoops MapCarE ); my @data = ( [ [1, "Darth Vader"], [3, "Luke Skywalker"], [5, "Obi Wan Kenobi"], ],[ [0, "Lighsabre "], [5, "Blaster"], [9, "Rocket launcher"], ],[ [10, "Dagobah"], [14, "Kashyyyk"], ], ); my @joined= NestedLoops( \@data, sub { my( $dig, $txt )= MapCarE { [ @_ ] } @_; [ join('',@$dig), join(', ',@$txt) ]; }, ); for( @joined ) { print join("\t",@$_), $/; }

    - tye        

Re: All Combinations of three arrays.
by jZed (Prior) on Aug 26, 2005 at 17:15 UTC
    Since what you want to do is un-normalize the tables, just do the reverse of what you'd normally do to normalize them :-).

    updateSheesh, it's a joke about first-normal form. There was a smiley. I'm sorry if this appeared to be belittling the OP's question, that wasn't my intention.