Сократить код: объединить массивы из хэшей - PullRequest
0 голосов
/ 21 сентября 2011

У меня есть список хэшей, и некоторые из хэшей содержат ключ, который предоставляет сам массив.

my @cars = (
   { # empty car
      name => "BMW",
   },
   { # car with passengers
      name => "Mercedes",
      passengers => [qw(Paul Willy)],
   },
   ...
)

Это почти как выше, но, конечно, не с примером глупых машин: -)

Теперь мне нужно получить список всех «пассажиров» из всех хэшей, включая те, которые даже не предлагают массив пассажиров.

На втором шаге мне нужно получить уникальные записи из списка(на самом деле пассажиры - это ссылки на объекты Perl, и каждый объект мне нужен один раз в списке)

На данный момент я делаю:

my (@all, @passengers, %seen);
for(@cars) {
    push @all, @{$_->{passengers}} if $_->{passengers};
}

@passengers = grep { ! $seen{$_} ++ } @all;

Я хотел бы избавиться от @all и броситьсписок всех пассажиров прямо в grep.

Есть предложения?

Ответы [ 3 ]

6 голосов
/ 21 сентября 2011
my %seen;
my @passengers = grep { ! $seen{$_} ++ }
                 map { @{$_->{passengers} || []} } @cars;
2 голосов
/ 21 сентября 2011

Мне мешает создать массив и ссылку только для того, чтобы немедленно избавиться от них обоих (как это сделал cjm), поэтому я бы использовал

my %seen;
my @passengers =
   grep !$seen{$_}++,
   map $_ ? @$_ : (),
   map $_->{passengers},
   @cars;

или

my %seen;
my @passengers =
   grep !$seen{$_}++,
   map @{ $_->{passengers} },
   grep $_->{passengers},
   @cars;
1 голос
/ 21 сентября 2011

Вот еще один вариант. Используется List::MoreUtils::uniq. Материал %seen хорошо знать, но в наши дни он не нужен.

use List::MoreUtils qw<uniq>;

my @passengers 
    = sort uniq map { @$_ } grep { defined } map { $_->{passengers} } @cars
    ;

Конечно, используя мою идиому list_if, я бы просто сделал это:

 my @passengers = sort uniq map { list_if( $_->{passengers} ) } @cars;

Где list_if определяется как:

sub list_if {
    use Params::Util qw<_ARRAY _HASH>;

    return unless my $cond = shift;
    return unless my $ref
        = @_ == 0 ? $cond
        : @_ == 1 ? $_[0]
        :          \@_
        ;
    return !ref( $ref )   ? $ref
         : _ARRAY( $ref ) ? @$ref
         : _HASH( $ref )  ? %$ref
         :                  ()
         ;              
}

Это была полезная идиома для сокращения длинных подходов к принятию решения о том, «потоковые» массивы и ссылки на хэш или нет.

...