Можно ли избежать ссылки + разыменования хэша, возвращенного из операции карты? - PullRequest
4 голосов
/ 06 апреля 2011

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

my @obs = ({
   value => 'three',
   id => 3
},{
   value => 'one-2',
   id => 1
},{
   value => 'one',
   id => 1
});
# This works, prints "one\nthree"
say for values %{{ map { $_->{id} => $_->{value} } @obs }};

Можно ли избежать бита ссылки + разыменования вокруг map?Сначала я попытался просто вызвать values непосредственно при возврате из map, но в Perl его не будет:

Тип аргумента 1 для значений должен быть хешем (не итератором карты) в скрипте\ workbench.pl строка 55, рядом с "@obs;"

Ответы [ 2 ]

7 голосов
/ 06 апреля 2011

Проблема в том, что values действительно, очень хочет, чтобы хеш работал.Это потому, что он особенный: он очищает заполнитель, используемый each.Требуется фактический объект, чтобы очистить это.

Вы можете пойти одним из двух способов здесь.Во-первых, если вам не нравится ref / deref, вы можете просто вытащить создание временного хэша из однострочного (пожалуйста, выберите более точное имя, чем %h для вашего фактического кода):

my %h = map { $_->{id} => $_->{value} }  @obs;
say for values %h;

Если вы не хотите, чтобы %h зависал, просто поместите его во временный блок:

...code code code...
{
    my %h = map { $_->{id} => $_->{value} }  @obs;
    say for values %h;
}
...code code code...

Другим подходом может быть эмуляция создания вашего временного хеша, и valuesделать:

my %seen;
for ( reverse @obs ) { say $_->{value} unless $seen{$_->{id}}++ }

Что действительно важно, так это то, что вы собираетесь делать с этими данными.Если вам просто нужны значения вашего инвертированного хэша только один раз, то ваш однострочный может быть лучшим решением.Если вам понадобятся эти данные (id и значение) позже, то создайте реальный хеш и используйте его - не делайте это преобразование более одного раза, чтобы вы могли сохранить их как однострочные.

Без дальнейшего контекста трудно дать совет, какой подход выбрать.

0 голосов
/ 07 апреля 2011

Если бы values работал над списком, он занял бы каждый второй элемент этого списка. Так

say for values %{{ map { $_->{id} => $_->{value} } @obs }};

будет

say for every_odd map { $_->{id} => $_->{value} } @obs;

Теперь вполне возможно написать такую ​​функцию, но в этом случае она просто не нужна. Можно просто сделать

say for map { $_->{value} } @obs;

И это упрощает до

say $_->{value} for @obs;

Один улов: не используя хеш, вы не удаляете дубликаты.

...