Perl中等效于(Python)列表推导的写法

13 投票
3 回答
8530 浏览
提问于 2025-04-15 12:49

我在寻找将这个Python代码片段用Perl表达的方法:

data = {"A": None, "B": "yes", "C": None}
key_list = [k for k in data if data[k]]  
# in this case the same as filter(lambda k: data[k], data) but let's ignore that

从一个角度来看,我只想要那些值为Noneundef的键。从另一个角度来看,我想要的是一个简洁的Perl写法,类似于带条件的列表推导式

3 个回答

6

如果你想看看这个主题的不同变种,可以去看看autobox(它的实现有autobox::CoreMoose::Autobox

use autobox::Core;

my %data = ( A => undef, B => 'yes', C => undef );
my $key_list = %data->keys->grep( sub { defined $data{$_} } );

say "Key: $_" for @$key_list;

# => Key: B


Moose::Autobox 提供了一个键值对的 'kv' 功能,这样可以让代码更简洁:

my $key_list = %data->kv->grep( sub{ defined $_->[1] } )->map( sub{ $_->[0] } );

这里有一个更详细甚至更长的版本:

my $key_list = %data->kv
                    ->grep( sub { my ($k, $v) = @$_; defined $v } )
                    ->map(  sub { my ($k, $v) = @$_; $k }         );
13

使用 grep

#!/usr/bin/perl

use strict;
use warnings;

my %data = ("A" => 0, "B" => "yes", "C" => 0 );
my @keys = grep { $data{$_} } keys %data;

grep 会返回右边列表中那些符合大括号内表达式的值,也就是说,只有当表达式的结果为真时,才会返回这个值。正如 telemachus 提到的,你需要理解 Perl 中的真和假值。这个问题 对 Perl 中的真值有个很好的概述。

你可能还想了解一下 map,它会对列表中的每个元素应用大括号内的表达式,并返回结果。举个例子:

my @data = ("A" => 0, "B" => 1, "C" => 0 );
my @modified_data = map { $data{$_} + 1 } @data;
print join ' ', @data, "\n";
print join ' ', @modified_data, "\n";
20

我觉得你想要的是 grep

#!/usr/bin/env perl
use strict;
use warnings;

my %data = ( A => undef, B => 'yes', C => undef );

my @keys = grep { defined $data{$_} } keys %data;

print "Key: $_\n" for @keys;

我也觉得我打字太慢了,应该在发布答案之前先刷新一下页面。顺便说一下,0 或者 undef 都可以用来处理 空值,但要记得你用的是哪个。在 Perl 里,假值和未定义值是不同的。具体来说:undef 在布尔测试中返回假,但 0 也是如此。如果 0 是一个有效的值,那你就要明确测试它是否被定义,而不仅仅是测试它的真假。(我提到这个是因为 James 选择了 0,而我选择了另一种方式,你可能知道也可能不知道这是否重要。)

撰写回答