Like grep but returns the first match. successive calls return successive elements.
This was the solution to a reference problem
I was working on awhile back. It was one of those things that I wanted to do, just to do it because it should be possible. (Have a sub that remembers some context info.)
Plus I like the construct :).
#!/usr/bin/perl
######################################################################
+###############
# findone
# usage: findone { coderef }, @array , OPTIONAL start_index OPTIONAL
+end_index
# Like grep but returns the first match. successive calls return succe
+ssive elements.
# Can be nested. Uses Weak references to prevent the leaking of memory
+.
######################################################################
+###############
BEGIN {
use warnings;
use strict;
use WeakRef;
my %find_cache = (); # Temporary Storeage.
sub findone(&\@;$$) {
my $coderef = shift ;
# Generate a key from the caller function so we can track whic
+h call it is.
my $codekey = join(":",caller(),"$_[0]"); # Generate key
my %persistant_args = () ;
##############################################################
+##########
# Clean up old keys to prevent leaking mem. If the data does
+not exist,
# then it has been freed and we don't need to keep position in
+fo.
##############################################################
+##########
while(my ($k,$v) = each %find_cache){
delete $find_cache{$k} unless defined ($v->{dataref});
}
unless (defined $find_cache{$codekey} ){
%persistant_args = ('index' =>($_[1]||0), 'dataref' => $_[
+0] );
}else{
%persistant_args = %{$find_cache{$codekey}};
}
my $end_index = $_[2] || $#{ $_[0] };
for (; $persistant_args{index} <= $end_index; $persistant_ar
+gs{index}++ ){
$_ = $_[0]->[$persistant_args{index}];
if (&$coderef){
$persistant_args{index}++;
$find_cache{$codekey} = {%persistant_args};
weaken ($find_cache{$codekey}->{dataref});
return wantarray ? ($_ ,($persistant_args{index} -1 )
+ ) : $_;
}
}
delete $find_cache{$codekey};
return;
}
}
###########################
# Silly Example #
###########################
my @words = (qw(this Is a silly coNtrived Test)) x 5;
print "\@words is $#words\n";
while ( my ( $val ,$index ) = findone { m/[A-Z]/ } @words ){
print "_" x 40,"\n";
print "Matched uppercase letter $val at $index \n";
while ( my ( $otherval ,$otherindex ) = findone { !m/[A-Z]/ }
+@words , 10, 22 ){
print "\tInner matched all lower $otherval at $otherindex\n";
}
sleep(1);
}
updated Changes in response to jynx
updated Changed to accept end_index as well.
updated Changed to use stringified reference in cache key. Now you can nest them.
my @AoA = (Array of arrays);
while ( my ($val,$index) = findone { findone{ other_criteria } @{$_} } @AoA ){
}
UPDATE: Subtle Bug/Feature, see this. I have a newer version that uses Filter::Simple, but I still hope to fix this without resorting to it.
UPDATE: Rough filter simple version here.
-Lee
"To be civilized is to deny one's nature."
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
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, 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, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
Outside of code tags, you may need to use entities for some characters:
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.
|
|