Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Thank you

by l3nz (Friar)
on Jan 19, 2004 at 16:10 UTC ( [id://322372]=note: print w/replies, xml ) Need Help??


in reply to Turning a recursive function into an iterator

In the end I was able to do more or less what I had in mind at the beginning. This implementation is recursive (I wanted to mix in both things) but behaves like an iterator using the closure: It uses two queues (one for read filenames and another for directories to be read) but when a directory is read it iterates over itself until a file is found; still, the interface is an iterator.
{ my @fq; # files my @dq; # directories my $currentDir; sub initDir { push @dq, shift; }; sub getNextFile { my $f; if ( $#fq >= 0 ) { $f = pop @fq; } else { if ( $#dq >= 0 ) { my $r; # filename read local *D; $currentDir = pop @dq; opendir(D, $currentDir) || die "$currentDir: $!"; while ( defined( $r = readdir( D ) ) ) { next if $r =~ /^\.{1,3}$/; my $ff = $currentDir . '/' . $r; if ( -d $ff ) { push @dq, $ff; } else { push @fq, $ff; } } closedir D; $f = getNextFile(); } else { $f = undef; } } return $f; } } my $dir = "c:/inetpub"; # execution start here initDir( $dir ); my $f; my $i = 0 ; while ( defined( $f = getNextFile() ) ) { $i++; print "[$i] $f \n"; }
What do you think about it? is there anything fundamentally flawed with this approach?

Replies are listed 'Best First'.
Re: Thank you
by sfink (Deacon) on Jan 19, 2004 at 21:33 UTC
    To me, recursion means "let the programming language manage the stack", so the use of either an explicit stack or queue bothers me when I'm trying to do things recursive-like.

    So here's a somewhat more fully iterator-style solution that uses the dirhandle as an iterator, and keeps a single scalar as the memory between invocations. Oh, and this isn't totally necessary, but I convert simple files to iterators that return the file once. I'm doing that because whenever I write iterators, I always use pretty much the same pattern: compute the next value if needed, consume a result from a sub-iterator, then return it. This allows a class hierarchy of iterators that override only the minimum necessary operations. Anyway, here's the code:

    use IO::Dir; sub make_reader2 { my ($dirname) = @_; my $d = new IO::Dir $dirname or die "opendir $dirname: $!"; my $next; return sub { while (1) { unless (defined $next) { my $entry = $d->read or return; next if $entry eq '.'; next if $entry eq '..'; $entry = "$dirname/$entry"; if (-d $entry) { $next = make_reader2($entry); } else { $next = sub { my $r = $entry; undef $entry; $r; }; } } my $result = $next->(); return $result if defined $result; undef $next; } }; } my $reader = make_reader2($ARGV[0]); print "$_\n" while (defined($_ = $reader->()));
•Re: Thank you
by merlyn (Sage) on Jan 19, 2004 at 16:13 UTC
      Yes, of course; but this was just a way to play around with both ideas and learn something. I would never waste a couple of hours studying a problem that's already solved if it's not to learn something from it :-)
Re: Thank you
by diotalevi (Canon) on Jan 19, 2004 at 19:31 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://322372]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (9)
As of 2024-04-23 11:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found