<?xml version="1.0" encoding="windows-1252"?>
<node id="147423" title="findone { coderef } @array" created="2002-02-25 18:22:38" updated="2005-08-09 23:57:39">
<type id="1042">
CUFP</type>
<author id="75719">
shotgunefx</author>
<data>
<field name="doctext">
Like grep but returns the first match. successive calls return successive elements.
&lt;br&gt;
This was the solution to a reference &lt;a href="http://www.perlmonks.org/index.pl?node_id=112053"&gt;problem&lt;/a&gt; 
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.)
&lt;br&gt;Plus I like the construct :).
&lt;readmore&gt;
&lt;code&gt;
#!/usr/bin/perl
#####################################################################################
# findone
# usage: findone { coderef }, @array  , OPTIONAL start_index OPTIONAL end_index
# Like grep but returns the first match. successive calls return successive 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(&amp;\@;$$) {	
	
	    my $coderef = shift ;
		# Generate a key from the caller function so we can track which 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 info.
		########################################################################
		while(my ($k,$v) = each %find_cache){
			delete $find_cache{$k} unless defined ($v-&gt;{dataref});
		}

		unless (defined $find_cache{$codekey} ){
			%persistant_args = ('index' =&gt;($_[1]||0), 'dataref' =&gt; $_[0] );
		}else{
			%persistant_args = %{$find_cache{$codekey}};
			
		}

		my $end_index = $_[2] || $#{ $_[0] };
		for  (; $persistant_args{index} &lt;=  $end_index; $persistant_args{index}++ ){
			$_ = $_[0]-&gt;[$persistant_args{index}];

			if (&amp;$coderef){
				$persistant_args{index}++;
				$find_cache{$codekey} = {%persistant_args};
				weaken ($find_cache{$codekey}-&gt;{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);
}
&lt;/code&gt;
&lt;b&gt;updated&lt;/b&gt; Changes in response to jynx&lt;br&gt;
&lt;b&gt;updated&lt;/b&gt; Changed to accept end_index as well.&lt;br&gt;
&lt;b&gt;updated&lt;/b&gt; Changed to use stringified reference in cache key.&lt;br&gt; Now you can nest them.&lt;br&gt;
&lt;pre&gt;
my @AoA = (Array of arrays);

while ( my ($val,$index) = findone { findone{ other_criteria } @{$_} } @AoA ){

}
&lt;/pre&gt;
&lt;B&gt;&lt;font size=+1&gt;UPDATE: &lt;/font&gt;&lt;/B&gt;Subtle Bug/Feature, see &lt;a href="http://www.perlmonks.org/index.pl?node_id=147752"&gt;this.&lt;/a&gt; I have a newer version that uses Filter::Simple, but I still hope to fix this without resorting to it.
&lt;BR&gt;&lt;B&gt;&lt;font size=+1&gt;UPDATE: &lt;/font&gt;&lt;/B&gt;Rough filter simple version &lt;a href="http://www.perlmonks.org/index.pl?node_id=148032"&gt;here&lt;/a&gt;.
&lt;br&gt;&lt;br&gt;
-Lee
&lt;br&gt;&lt;br&gt;
"To be civilized is to deny one's nature."</field>
</data>
</node>
