On 27/02/2012 02:30, Steve Bertrand wrote:
I came across a question early this morning on a forum that intrigued
me. I literally spent about five hours trying everything to solve it,
but I couldn't.

Every attempt at recursion, counting, numbering, hashing etc failed. Is
there a way to use recursion to eliminate the repeated and
pre-calculated calls to foreach as this OP is asking?

 From ... .. ... is verbatim 'dms000'

...

I need to generate a list of combinations from a data structure such as:

my $attributes =
[
{ type => 'colors', values => [qw/red green blue/] },
{ type => 'sizes', values => [qw/small large/] },
{ type => 'shades', values => [qw/light dark/] },
];

It is easy enough when the number of "types" are known:

my @combos = ();
foreach my $a (@{$attributes->[0]->{values}}) {
foreach my $b (@{$attributes->[1]->{values}}) {
foreach my $c (@{$attributes->[2]->{values}}) {
push @combos, [$a, $b, $c];
}
}
}

Which results in a list such as:
red small light
red small dark
red large light
red large dark
green small light
...

But how to do with arbitrary number of types? Obviously will need
recursion but I can't figure it out. The only thing I could come up with
was generating code like code2 as a string and eval()ing it...a poor
solution.

...

I know this isn't a beginner's question, but I know there are geniuses
here. Is there a way to simplify this within Perl?

Hi Steve

Much of the complexity comes from working with the nested data
structure. Writing a subroutine that takes just a set of the 'values'
arrays cleans things up a lot. Take a look at the program below.

HTH,

Rob


use strict;
use warnings;

my $attributes = [
  { type => 'colors',  values => [qw/red green blue/]  },
  { type => 'sizes',   values => [qw/small large/] },
  { type => 'shades',  values => [qw/light dark/] },
];

print "$_\n" foreach combos(map $_->{values}, @$attributes);

sub combos {

  my $first = shift;

  return @$first unless @_;

  my @combinations;

  foreach my $beg (@$first) {
    foreach my $end (combos(@_)) {
      push @combinations, "$beg $end";
    }
  }

  return @combinations;
}

**OUTPUT**

red small light
red small dark
red large light
red large dark
green small light
green small dark
green large light
green large dark
blue small light
blue small dark
blue large light
blue large dark

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to