Perl-эквивалент (Python-) понимания списка - PullRequest
13 голосов
/ 11 июля 2009

Я ищу способы выразить этот фрагмент 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

Итак, с одной стороны, я просто хочу получить ключи, значения которых Нет или undef . С другой стороны, я хочу получить краткий perl-эквивалент списка с условным .

Ответы [ 3 ]

21 голосов
/ 11 июля 2009

Я думаю, что вы хотите 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 может быть хорошим способом обработки значений null , но убедитесь, что вы помните, какое из них используете. Ложное значение и неопределенное значение - не одно и то же в Perl. Для пояснения: undef возвращает false в булевом тесте, но также и 0. Если 0 является допустимым значением, то вы хотите явно проверить на определенность, а не просто на истинность. (Я упоминаю об этом, потому что Джеймс пошел на 0, а я пошел другим путем, и вы можете или не можете знать, если это имеет значение.)

13 голосов
/ 11 июля 2009

Использование 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";
6 голосов
/ 11 июля 2009

Для изменения темы посмотрите autobox (см. Его реализации autobox :: Core и Moose :: 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', что делает код DRYer:

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 }         );
...