ewok
ewok

Reputation: 21493

perl: grep and map in one operation

Is there a way to perform a grep and a map in a single operation in perl? Similar to the way that python can perform list comprehension:

files = [{ 'path':'/path/to/file1',
           'size':123},
         { 'path':'/path/to/file2',
           'size':987},
         { 'path':'/path/file3',
           'size':1234},
         { 'path':'/path/to/file4',
           'size':543},
         { 'path':'/path/to/my/file5',
           'size':1357}]
large_filepaths = [file['path'] for file in files if file['size'] > 1024]

In Perl, I need to do a grep to filter out the large files, then a map to get the specific values I want:

my $files = [ { path=>'/path/to/file1',
                size=>123},
              { path=>'/path/to/file2',
                size=>987},
              { path=>'/path/file3',
                size=>1234},
              { path=>'/path/to/file4',
                size=>543},
              { path=>'/path/to/my/file5',
                size=>1357} ];
my @large = grep { $_->{size} > 1024 } $files;
my @large_filepaths = map { $_->{path} } @large;

Is there a simple way to run this in a single operation, or do I have to use 2 statements (or one compound statement)?

Upvotes: 3

Views: 3524

Answers (4)

Borodin
Borodin

Reputation: 126742

You can do this with just a call to map if you want

my @large_filepaths = map { $_->{size} > 1024 ? ( $_->{path} ) : ( ) } @$files;

but I think a combined map/grep is clearer.

Upvotes: 2

hobbs
hobbs

Reputation: 240472

One statement with map { ... } grep { ... } @$files is the "standard" way to do it and the closest equivalent to what you're doing in Python.

Technically it's possible to do it in a single map, because map can return any number of values for each input value, including zero ­— so you can do something like
map { $_->{size} > 1024 ? $_->{path} : () } @$files, but that's substantially less clear and I wouldn't recommend it in general.

Upvotes: 10

Sinan Ünür
Sinan Ünür

Reputation: 118156

  1. $files is an array reference, therefore values $files does not make sense.

  2. map BLOCK and grep BLOCK tend to be slower than map EXPR and grep EXPR, respectively. Prefer the latter if you can.

my @large_filepaths =
    map $_->{path},
    grep $_->{size} > 1024,
    @$files;

Upvotes: 4

Alnitak
Alnitak

Reputation: 339965

Is there a simple way to run this in a single operation,

You can do it as one compound statement:

my @large_paths = map { $_->{path} } grep ...;

Upvotes: 2

Related Questions