Thanks to everyone for all the responses. Set::CrossProduct does indeed do exactly what I wanted, except that the real problem I'm working with wasn't using straight arrays, and it seemed complicated to get Set::CrossProduct to do what I wanted with the inputs I have.
So, in case you're interested, here's the solution I came up with in the end. I've just included one element of the DATA hash at the end; there are lots like that. Any comments or suggestions you have would be welcomed.
local $\ = "\n";
local $/ = '';
open CODES, "> $code_file" or die "Couldn't open codefile: $!\n";
my $csv = Text::CSV->new;
$csv->combine('code', 'desc');
print CODES $csv->string;
my %hash = eval <DATA>;
my @full_code_list = ();
foreach my $key (keys %hash) {
print "Looking at code [$key]...\n";
my @list = gen_codes($hash{$key});
push @full_code_list, @list if @list;
}
foreach my $aref (@full_code_list) {
my ($code, $desc) = @$aref;
$csv->combine($code, $desc);
print CODES $csv->string;
}
sub gen_codes {
my $href = shift;
my $source = $href->{'source'};
my $base_desc = $href->{'desc'};
my @codes = ();
my @element_hashes = @$href{@{$href->{'elements'}}};
my $code_str_sub = $href->{'code_str'};
my $desc_str_sub = $href->{'desc_str'};
my @code_args = ($source);
my @desc_args = ($base_desc);
sub getvalues {
my ($elems, $codes, $c_sub, $d_sub, $code_args, $desc_args) =
+@_;
my ($element, @remaining_elems) = @$elems;
for my $code (keys %$element) {
my $desc = $element->{$code};
my $c_args = [ @$code_args, $code ];
my $d_args = [ @$desc_args, $desc ];
if (@remaining_elems) {
getvalues(\@remaining_elems, $codes, $c_sub, $d_sub, $
+c_args, $d_args);
} else {
push @$codes, [&$c_sub(@$c_args), &$d_sub(@$d_args)];
}
}
}
getvalues(\@element_hashes, \@codes, $code_str_sub, $desc_str_sub,
+ \@code_args, \@desc_args);
return @codes;
}
__END__
my %hash = (
'FI_SWP_PLAIN_VANILLA-SPREADS' => {
source => 'FDER,SWAPSPRD',
desc => 'Swaps - Plain Vanilla Spreads',
elements => [qw/term attr/],
term => {
'2Y' => '2 Years',
'3Y' => '3 Years',
'4Y' => '4 Years',
'5Y' => '5 Years',
'6Y' => '6 Years',
'7Y' => '7 Years',
'8Y' => '8 Years',
'9Y' => '9 Years',
'10Y' => '10 Years',
'12Y' => '12 Years',
'15Y' => '15 Years',
'20Y' => '20 Years',
'25Y' => '25 Years',
'30Y' => '30 Years',
'40Y' => '40 Years'
},
attr => {
RT_MID => 'Mid Rate',
RT_BID => 'Bid Rate',
RT_OFF => 'Offer Rate',
AM_MOD_DUR => 'Modified Duration',
DT_VALUE => 'Value Date',
DT_MATURITY => 'Maturity Date'
},
code_str => sub {
my ($s,$t,$a) = @_;
return "DB($s,$t,$a)";
},
desc_str => sub {
my ($d,$t,$a) = @_;
return "$d: $t $a";
}
}
);
|