Могу ли я вернуть несколько пар из карты, переданной в хэш?

Я пытаюсь создать хэш, который ищет ключ или значение. Чтобы искать в обоих направлениях, я хочу, чтобы значения были ключами (со значениями, которые являются их ключами).

<
H He
>
    ==> map( {
        state $n = 0; $n++;
        $n     => $_.Str,
        $_.Str => $n
         } )
    ==> my %elements;

%elements.perl.say;

%elements{2}.WHAT.say;

Это дает мне эту странную вещь:

{"1\tH H\t2" => $(2 => "He", :He(2))}
(Any)

Только с одной парой все в порядке:

<
H He
>
    ==> map( {
        state $n = 0; $n++;
        $n     => $_.Str
         } )
    ==> my %elements;

%elements.perl.say;

%elements{2}.WHAT.say;

Теперь я получаю то, что хочу, но без обратной пары:

{"1" => "H", "2" => "He"}
(Str)

person brian d foy    schedule 03.09.2016    source источник
comment
Я бы использовал map( { ++$ => ~$_ } ) или <H He> Z=> 1..* для создания начального набора пар.   -  person Brad Gilbert    schedule 08.09.2016


Ответы (1)


Ваш map возвращает последовательность значений List, каждое из которых содержит два Pair values.
Передача этого в хэш не приведет к его автоматическому сглаживанию, и каждый List становится ключом или значением хеша.

Есть несколько способов заставить его делать то, что вы хотите:

Использование flat

Вы можете использовать встроенную функцию flat, чтобы сгладить результат map, чтобы хэш получил последовательность Pair :

<H He>
==> map {
    (state $n)++;
    +$n => ~$_,
    ~$_ => +$n
}\
==> flat()
==> my %elements;

%elements.say;          # {1 => H, 2 => He, H => 1, He => 2}
%elements{2}.WHAT.say;  # (Str)

И map, и flat возвращают ленивые последовательности, так что это (теоретически) эффективно использует память, даже если список элементов велик.

  • Примечание: я также написал +$n вместо $n, потому что оператор построения => Pair (как и оператор построения , List) не "деконтейнеризирует" свои аргументы - если вы дадите ему такой контейнер элемента как переменная $, она будет привязана к ней напрямую, а не к содержащемуся в ней значению, что приводит к тому, что следующее $n++ также влияет на Pair, возвращенное из предыдущей итерации. Предоставление оператору построения пары выражения значения вместо переменной позволяет избежать этого.

Использование slip

slip — это внутренняя версия flat:

<H He>
==> map {
    (state $n)++;
    slip
        +$n => ~$_,
        ~$_ => +$n
}\
==> my %elements;

Каждая итерация map теперь возвращает значение типа Slip, которое точно такое же, как List, за исключением того, что оно автоматически растворяется в любом родительском элементе. список, частью которого он становится.

Рефакторинг

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

my @keys = 1..*;
my @values = <H He>;
my %elements = flat (@keys Z=> @values), (@values Z=> @keys);

Or:

my %elements = 1..* Z=> <H He>;
push %elements, %elements.invert;

(Z — метаоператор "zip")

person smls    schedule 04.09.2016