map can't handle recursion.
Of course you can have a map block inside a function, and recurse into that from inside the map block:
sub hash_filter {
my $source = shift;
my $filter = shift;
return {
map {
ref $filter->{$_} eq 'HASH'
? ref $source->{$_} eq 'HASH'
? ($_, hash_filter( $source->{$_}, $filter->{$_} ))
: croak "bad filter: on '$_', expected HASH\n"
: ($_, $source->{$_})
} grep {
exists $source->{$_}
} keys %$filter
}
}
which btw is the for loop of the OP rewritten in terms of map/grep.
update: a terse version which eliminates shifting @_ and working directly on the arguments (which aren't altered by the function):
sub hash_filter {
return {
map {
ref $_[1]->{$_} eq 'HASH'
? ref $_[0]->{$_} eq 'HASH'
? ($_, hash_filter( $_[0]->{$_}, $_[1]->{$_} ))
: croak "bad filter: on '$_', expected HASH\n"
: ($_, $_[0]->{$_})
} grep { exists $_[0]->{$_} } keys %{$_[1]}
}
}
Now that's arguably micro-optimized and far less readable (11 lines) than the OP's code (18 lines) imho.
More elegant? Perhaps for those who prefer nested ?: statements for simple expressions over if/else blocks...
update 2: B::Concise shows identical optrees (execpt line numbers) for the "for" and "map/grep" solutions.
perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
|