The perl equivalent of understanding Python lists with a built-in if statement?

In python, I can do the following to get all the objects in a list with a specific property. In this example, I grab the list of id fields of each obj in the objs list, where obj.id greater than 100:

 ids = [ obj.id for obj in objs if obj.id > 100] 

How will I do the same in perl? I think I want to use map , but I don’t know how to conditionally display elements from a source set to the target set.

+6
python perl
source share
4 answers

The map block can return 0 or more elements for each element in the source list. To omit an element, simply return an empty list () :

 my @ids = map { $_->id > 100 ? $_->id : () } @objs; 

This assumes that the objects in @objs have an id attribute and associated access. If you want direct hash access, you can also do this:

 my @ids = map { $_->{id} > 100 ? $_->{id} : () } @objs; 

Or you can just combine map and grep :

 my @ids = map { $_->id } grep { $_->id > 100 } @objs; # Or reverse the order to avoid calling $_->id twice: my @ids = grep { $_ > 100 } map { $_->id } @objs; 

I'm not sure which one would be more efficient, but if @objs really big, it hardly matters.

If the value you are extracting from the object is expensive to calculate, you can cache the value for the test and return value:

 my @vals = map { my $v = $_->expensive_method; $v > 100 ? $v : () } @objs; 
+13
source share

Use grep to return only those items that match the condition. It is like filter in other languages.

grep { condition } @array

For example:

 my @nums = (1, 50, 7, 105, 200, 3, 1000); my @numsover100 = grep { $_ > 100 } @nums; foreach my $num (@numsover100) { print $num . "\n"; } 
+2
source share

Perhaps you could combine with map and filter , which was essentially what we did in Python before we understood the list.

+1
source share

Using map and grep together goes over the list twice. Create your own:

 sub fancy_filter { my ($map_block, $grep_block, @list) = @_; my @results; foreach my $item (@list) { local $_ = $item; if ($grep_block->()) { push @results, $map_block->(); } } return @results; } my @ids = fancy_filter( sub { $_->{id} }, # map block sub { $_->{id} > 100 }, # grep block @id_list, ) 
0
source share

All Articles