Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: Using Loop or Map/Grep?

I'm writing a program to step through a directory tree (Yes, I know about File::Find, but I'm writing a replacement).

In my program, I'm doing a readdir on a whole directory and placing it in a list. I need to do two things:

  1. Remove . and .. from the list
  2. Prepend the current directory name on each file.

I can do this with a loop, or I can use map and grep:

# Map and Grep

my @dir_stack = readdir $dir_fh;;
@dir_stack = grep { !/^\.{1,2}$/ } @dir_stack;
@dir_stack = reverse map { "$cwd/$_" } @dir_stack;
push @stack, @dir_stack;

# Read Loop

opendir $dir_fh, $cwd;
my @dir_stack;
foreach my $file (readdir $dir_fh) {
    next if $file =~ /^\.{1,2}$/;   #Skip "." and ".."
    unshift @dir_stack, "$cwd/$file";
}
push @stack, @dir_stack;

What about combining grep and map?

 opendir $dir_fh, $cwd;
 my @dir_stack = readdir $dir_fh;;
 @dir_stack = grep { !/^\.{1,2}$/ && {$_ = "$cwd/$_"} } @dir_stack;
 push @stack, reverse @dir_stack;

I want my code to be readable next week when I look at it and try to figure out what's going on. I also need my code to be efficient.

like image 325
David W. Avatar asked Dec 12 '11 19:12

David W.


1 Answers

Modifying $_ in grep? yuck! And what's with using an anon hash constructor?

@dir_stack = grep { !/^\.{1,2}$/ && {$_ = "$cwd/$_"} } @dir_stack;

should be

@dir_stack = map { /^\.\.?\z/ ? () : "$cwd/$_" } @dir_stack;

But I personally find using both map and grep more readable than combining them.

push @stack,
   reverse
    map "$cwd/$_",
     grep !/^\.\.?\z/,
      readdir $dh;

The need for reverse is rather odd, and it's much more visible here than hiding as a unshift, so that's another bonus.

like image 192
ikegami Avatar answered Sep 21 '22 17:09

ikegami