in reply to A more elegant way to filter a nested hash?

Looks good for me, map can't handle recursion.

The normal approach for nested data is to write a recursive "walker" and that's what you did.

The only tip I could probably have is trying hash slices as filters, but only if performance mattered.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

  • Comment on Re: A more elegant way to filter a nested hash?

Replies are listed 'Best First'.
Re^2: A more elegant way to filter a nested hash?
by shmem (Chancellor) on May 31, 2018 at 10:15 UTC
    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'

      Thanks for the example of how this can be done. I was scratching my head trying to figure out how to handle the recursion with map.

      πάντων χρημάτων μέτρον έστιν άνθρωπος.