在python中,我可以执行以下操作来获取具有特定属性的列表中的所有对象。在此示例中,我获取id
大于100的列表obj
中每个objs
的{{1}}个字段列表:
obj.id
我如何在perl中做同样的事情?我想我想使用ids = [ obj.id for obj in objs if obj.id > 100]
,但我不知道如何有条件地将项目从原始集映射到目标集。
答案 0 :(得分:13)
map
块可以为原始列表中的每个元素返回0个或更多元素。要省略元素,只需返回空列表()
:
my @ids = map { $_->id > 100 ? $_->id : () } @objs;
这假设@objs
中的对象具有id
属性和关联的访问者。如果您想要直接哈希访问,也可以这样做:
my @ids = map { $_->{id} > 100 ? $_->{id} : () } @objs;
或者,您只需合并map
和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;
我不确定哪些会更有效率,但除非@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)
答案 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,
)