I'm trying to create a hash that looks up by key or value. To look up both ways, I want the values to be keys (with values that are their keys).
<
H He
>
==> map( {
state $n = 0; $n++;
$n => $_.Str,
$_.Str => $n
} )
==> my %elements;
%elements.perl.say;
%elements{2}.WHAT.say;
This gives me this weird thing:
{"1\tH H\t2" => $(2 => "He", :He(2))}
(Any)
With only one pair, it's fine:
<
H He
>
==> map( {
state $n = 0; $n++;
$n => $_.Str
} )
==> my %elements;
%elements.perl.say;
%elements{2}.WHAT.say;
Now I get what I want, but without the reverse pair:
{"1" => "H", "2" => "He"}
(Str)
Your map
returns a sequence of List
values that each contain two Pair
values.
Feeding this to the hash won't automatically flatten it, and each List
becomes a key or value of the hash.
There are several ways to get it to do what you want:
flat
You can use the built-in flat
function to flatten the result of the map
, so that the hash receives a sequence of Pair
s:
<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)
Both map
and flat
return lazy sequences, so this is (in theory) memory-efficient even if the list of elements is large.
+$n
instead of $n
because the =>
Pair construction operator (like the ,
List construction operator) doesn't "decontainerize" its arguments - if you give it an item container such as a $
variable, it'll bind to that directly instead of the value contained in it, which causes the next $n++
to also affect the Pair
returned from the previous iteration. Giving the pair construction operator a value expression instead of a variable, avoids this.slip
slip
is the inside-out version of flat
:
<H He>
==> map {
(state $n)++;
slip
+$n => ~$_,
~$_ => +$n
}\
==> my %elements;
Each iteration of the map
now returns a value of type Slip
, which is just like List
except that it automatically dissolved into any parent list it becomes part of.
If you're not tied to your particular approach, here are two potentially clearer ways to generate the same hash:
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
is the "zip" meta-operator)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With