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.
In reply to Re^2: A more elegant way to filter a nested hash?
by shmem
in thread A more elegant way to filter a nested hash?
by jimpudar
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |