Perl相当于Python的嵌入if语句的列表推导?

时间:2011-01-20 23:44:36

标签: python perl

在python中,我可以执行以下操作来获取具有特定属性的列表中的所有对象。在此示例中,我获取id大于100的列表obj中每个objs的{​​{1}}个字段列表:

obj.id

我如何在perl中做同样的事情?我想我想使用ids = [ obj.id for obj in objs if obj.id > 100] ,但我不知道如何有条件地将项目从原始集映射到目标集。

4 个答案:

答案 0 :(得分:13)

map块可以为原始列表中的每个元素返回0个或更多元素。要省略元素,只需返回空列表()

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

这假设@objs中的对象具有id属性和关联的访问者。如果您想要直接哈希访问,也可以这样做:

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

或者,您只需合并mapgrep

my @ids = map { $_->id } grep { $_->id > 100 } @objs;

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

我不确定哪些会更有效率,但除非@objs真的很大,否则这不太重要。

如果从对象中提取的值计算起来很昂贵,那么您可以缓存测试的值并返回值:

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

答案 1 :(得分:2)

使用grep仅返回符合条件的项目。就像其他语言中的filter一样。

grep { condition } @array

例如:

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

答案 2 :(得分:1)

你可能会将mapfilter结合起来,这基本上就是我们在列表推导之前在Python中所做的。

答案 3 :(得分:0)

一起使用map和grep两次传递列表。建立自己的:

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,
)