Raku By Example
View me onGitHub
## Hashes
##-------

# Hashes are like an unordered arrays, where each value is associated 
# with a string (known as a key), rather than a positional index.

# Hashes use the % sigil and are created by enumerating pairs of keys and
# values.

my %person =
    name => 'Andreas',
    lastname => 'Stoa',
    age => 41;

say %person{'name'};           # accessing an element
%person{'age'} = 25;           # updating the value of an element
%person{'country'} = 'Greece'; # adding a new pair

# All values of a hash can have type constraints.
my Int %binaries = zero => 0, one => 1;

my %booleans of Bool = t => True, f => False; # similar thing

# The keys of a hash can also have type constraints.
my %doubles{Int} of Int; # constraining both keys and values

say %doubles{21} = 42;

## Some methods
##-------------

my %natural-satellites = ( # during assignment, pairs can be sorrounded by parens
    mercury => 0,
    jupiter => 79,
    venus   => 0,
    saturn  => 62,
    earth   => 1,
    nepture => 14,
    mars    => 2,
    uranus  => 27
);


# `keys` - returns a list of keys of the hash.
my @planets = %natural-satellites.keys;
say @planets; # (earth uranus nepture saturn venus mercury jupiter mars)

# `values` - returns a list of values of the hash.
my @satellites = %natural-satellites.values;
say @satellites; # (1 27 14 62 0 0 79 2) 

# `kv` - returns a list of both keys and values.
say %natural-satellites.kv; # (earth 1 uranus 27 nepture 14 saturn 62 venus 0
                            # mercury 0 jupiter 79 mars 2)

# `pairs` - returns a list of pairs (key/value).
say %natural-satellites.pairs; # (earth => 1 uranus => 27 nepture => 14
                               # saturn => 62 venus => 0 mercury => 0
                               # jupiter => 79 mars => 2)

# `antipairs` - returns a list of inverted pairs (value/key).
say %natural-satellites.antipairs; # (1 => earth 27 => uranus 14 => nepture
                                   # 62 => saturn 0 => venus 0 => mercury
                                   # 79 => jupiter 2 => mars)

# `elems` - returns number of pairs in the hash.
say %natural-satellites.elems; # 8

## Hash comphrehensions
##---------------------

my @numbers = 1, 2, 3, 4, 5;
my @letters = <A B C D E>;

# Postfix form of for and blocks can be combined to make list comphrehensions.
my %square-nums = %( {$_ => $_**2} for @numbers ); # %() is an alternative way of
                                                   # creating a hash.

say %square-nums;      # {1 => 1, 2 => 4, 3 => 9, 4 => 16, 5 => 25}

# Conditionals can be applied too.

my %square-even-nums = %( {$_ => $_**2} if $_ %% 2 for @numbers );
my %square-even-nums = %( {$_ => $_**2} if $_ !%% 2 for @numbers );

say %square-even-nums; # {2 => 4, 4 => 16}
say %square-odd-nums;  # {1 => 1, 3 => 9, 5 => 25}

# To obtain a one-to-correspondence, use the zip operator `Z`.
my @letters-nums =  %( {$_[0] => $_[1]} for @letters Z @numbers );

say @letters-nums;     # {A => 1, B => 2, C => 3, D => 4, E => 5}

# Or using the flat function.
my @letters-nums1 = %( flat @letters Z @numbers );

say @letters-nums1;    # {A => 1, B => 2, C => 3, D => 4, E => 5}


## bag union

my $a = bag <a a a b b c>;
my $b = bag <a b b b>;

say $a (|) $b;
say $a (&) $b;
say $a (+) $b;
say $a (.) $b;


## bags

my %words := Bag.new(slurp.comb(/\w+/).map(*.lc));

say "%words{}";

## count words

my %words;
for slurp.comb(/\w+/).map(*.lc) -> $word {
    %words{$word}++;
}

for %words.pairs.sort(-*.value).map({ $_.key, $_.value }) -> $word, $count {
    say "$word: $count";
}

## 散列

my %dev =  'pugs'=>'audreyt', 'pct'=>'pm', "STD"=>'larry';
my %same_dev = :rakudo('jnthn'), :testsuite('moritz');            # adverb (pair) syntax works as well
my %too_dev = ('audreyt', 'pugs', 'pm', 'pct', 'larry', "STD");  # lists get autoconverted in hash context
my %compiler = Parrot => {Rakudo => 'jnthn'}, SMOP => {Mildew => 'ruoso'};       # hash of hashes (HoH)
say %dev.perl;
say %same_dev.perl;
say %too_dev.perl;
say %compiler.perl;

# Hash Slices
my $name='pugs';
my $value = %dev{'pugs'};      # just give me the value related to that key, like in P5
my $value1 = %dev<STD>;         # <> autoquotes like qw() in P5
my $value2 = %dev<<$name>>;     # same thing, just with eval
say $value;
say $value2;

my @values = %dev{'pugs', 'STD'};
my @values2 = %dev<pugs STD>;
my @values3 = %dev<<pugs STD $name>>;
say @values;
say @values2;
say @values3;

say %compiler<Parrot><Rakudo>; # value in a HoH, returns 'jnthn'
say %compiler<SMOP>;           # returns the Pair: Mildew => 'ruoso'

# %dev   {'audrey'};         # error, spaces between varname and braces (postcircumfix operator) are no longer allowed
say %dev\  {'pugs'};        # works, quote the space
# %dev   .<dukeleto>;        # error
say %dev\ .{'pugs'};        # works too, "long dot style", because its its an object in truth 
say %dev.{'pugs'};


# Hash Methods
say 'this hash has some pairs' if ? %dev;                    # bool context, true if hash has any pairs
say 'this hash has '~ + %dev ~' pairs';                      # numeric context, returns number of pairs(keys)
say ~ %dev;                    # string context, nicely formatted 2 column table using \t and \n

my $table = %dev;             # same as ~ %dev
say $table;                   # ("pugs" => "audreyt", "pct" => "pm", "STD" => "larry").hash
say %dev.say;                 # stringified, but only $key and $value are separated by \t  #("pugs" => "audreyt", "pct" => "pm", "STD" => "larry").hash
my  @pairs = %dev;             # list of all containing pairs
say @pairs;                    # "pugs" => "audreyt" "pct" => "pm" "STD" => "larry"
say %dev.pairs;                 # same thing in all context  # "pugs" => "audreyt" "pct" => "pm" "STD" => "larry"
say %dev.elems;                 # same as + %dev or + %dev.pairs  # 3
say %dev.keys;                  # returns the list with all keys
say %dev.values;                # list of all values
say %dev.kv;                    # flat list with key1, value1, key 2 ...
say %dev.invert;                # reverse all key => value relations
say %dev.push(@pairs);         # inserts a list of pairs, if a key is already present in %dev, both values gets added to an array
# ("pugs" => ["audreyt", "audreyt"], "pct" => ["pm", "pm"], "STD" => ["larry", "larry"]).hash

my @another_pairs='Rakudo'=>'Perl6';
say %same_dev.push(@another_pairs);

## key-of

# You can also destructure hashes (and classes, which you'll learn about later !)
# The syntax is basically `%hash-name (:key($variable-to-store-value-in))`.
# The hash can stay anonymous if you only need the values you extracted.
sub key-of(% (:value($val), :qua($qua))) {
  say "Got val $val, $qua times.";
}

# Then call it with a hash: (you need to keep the brackets for it to be a hash)
key-of({value => 'foo', qua => 1});
my %hash = value => 'Perl6', qua => '2016';
key-of(%hash); # the same (for an equivalent `%hash`);


## pick 和 roll

my $bag = bag "red" => 2, "blue" => 10;
say $bag.roll(10); # 随机生成 10 组
say $bag.pick(*).join("\n");

$bag = bag "red" => 20000000000000000001, "blue" => 100000000000000000000;
say $bag.roll(10);
say $bag.pick(10).join(" ");

## 切片

# Semilists are semicolon lists

my %hash = a => {b => 2, c => 4};
say %hash{"a"}{"b"}.perl; # 2
say %hash{"a";"b"}.perl; # (2,) 

my @sliceable = [[ ^10 ], ['a'..'h'], [''..'']];
say @sliceable[ ^3; 4..6 ];

## SetHash

my $haԭ = SetHash.new();
$haԭ{'a'} = True;
say $haԭ, " in a ", $haԭ.^name;