A further level of abstraction and optimization can be provided by custom-compiling a subroutine optimized to perform the necessary task:
use strict; use UNIVERSAL 'isa'; sub build_deep_sub { my %options = @_; my $sub = q/ sub / . ( $options{proto} ? "($options{proto})" : '' ) +. q/ { / . ( $options{init} ) . q/ my ( @results, %seen ); while ( scalar @_ ) { my $target = shift; / . ( $options{guard} ? "next unless grep { $options{guard} } \$ +target;" : "" ) . q/ push @results, / . ( $options{map} ) . q/ $target; / . ( $options{post_order} ? 'push' : 'unshift' ) . q/ @_, / . ( $options{guard} ? " grep { $options{guard} }" : "" ) . q/ $seen{$target} ++ ? () : isa($target, 'HASH') ? %$target : isa($target, 'ARRAY') ? @$target : isa($target, 'REF') ? $$target : isa($target, 'SCALAR') ? $$target : (); } @results; } /; eval $sub or die "$@: $sub"; } my $type_search = build_deep_sub( init => 'my $type = shift;', map => +'grep isa( $_, $type ), ', guard => 'ref($_)' ); my @loggers = $type_search->( 'Log', $target );

The speed improvement of eliminating a round of subroutine calls will outway the one-time cost of the string eval unless your data structure to be searched is very small.

A library based on this approach could pre-generate a number of generally useful subroutines:

*{'deep_walk'} = build_deep_sub(); *{'deep_map'} = build_deep_sub( init => 'my $test = shift;', map => +'map $test->($_),' ); *{'deep_grep'} = build_deep_sub( init => 'my $test = shift;', map => + 'grep $test->($_),' ); *{'deep_grep_refs'} = build_deep_sub( init => 'my $test = shift;', m +ap => 'grep $test->($_),', guard => 'ref($_)' ); *{'deep_grep_type'} = build_deep_sub( init => 'my $type = shift;', m +ap => 'grep isa( $_, $type ), ', guard => 'ref($_)' );

(For what it's worth, the prototypes generated above don't seem to be quite right, but I'm sure that could be figured out with a bit of experimentation.)


In reply to Re^4: searching for an object reference by simonm
in thread searching for an object reference by Anonymous Monk

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.