class List
my class List does Iterable does Positional { }
List
stores items sequentially and potentially lazily.
Indexes into lists and arrays start at 0 by default.
You can assign to list elements if they are containers. Use Arrays to have every value of the list stored in a container.
List
implements Positional and as such provides support for
subscripts.
Immutability
Lists are immutable objects, i.e., neither the number of elements in a list nor the elements themselves can be changed. Thus, it is not possible to use operations that change the list structure itself such as shift, unshift, push, pop, splice and binding.
(1, 2, 3).shift; # Error Cannot call 'shift' on an immutable 'List'
(1, 2, 3).unshift(0); # Error Cannot call 'unshift' on an immutable 'List'
(1, 2, 3).push(4); # Error Cannot call 'push' on an immutable 'List'
(1, 2, 3).pop; # Error Cannot call 'pop' on an immutable 'List'
(1, 2, 3)[0]:delete; # Error Cannot remove elements from a List
(1, 2, 3)[0] := 0; # Error Cannot use bind operator with this left-hand side
(1, 2, 3)[0] = 0; # Error Cannot modify an immutable Int
A List
doesn't containerize its elements, but if
any element happens to be inside a Scalar container then
the element's contents can be replaced via an assignment.
my $a = 'z';
my $list = ($a, $, 'b');
say $list[0].VAR.^name; # OUTPUT: «Scalar», containerized
say $list[1].VAR.^name; # OUTPUT: «Scalar», containerized
say $list[2].VAR.^name; # OUTPUT: «Str», non-containerized
$list[0] = 'a'; # OK!
$list[1] = 'c'; # OK!
$list[2] = 'd'; # Error: Cannot modify an immutable List
Items, flattening and sigils
In Raku, assigning a List
to a scalar variable does not lose information.
The difference is that iteration generally treats a list (or any other list-like
object, like a Seq or an Array) inside a scalar as a
single element.
my $s = (1, 2, 3);
for $s { } # one iteration
for $s.list { } # three iterations
my $t = [1, 2, 3];
for $t { } # one iteration
for $t.list { } # three iterations
my @a = 1, 2, 3;
for @a { } # three iterations
for @a.item { } # one iteration
This operation is called itemization or putting in an item context.
.item
does the job for objects, as well as $( ... )
and, on array
variables, $@a
.
Lists generally don't interpolate (flatten) into other lists, except
when they are in list context and the single argument to an
operation such as append
:
my $a = (1, 2, 3);
my $nested = ($a, $a); # two elements
my $flat = $nested.map({ .Slip }); # six elements, with explicit Slip
my @b = <a b>;
@b.append: $a.list; # The array variable @b has 5 elements, because
# the list $a is the sole argument to append
say @b.elems; # OUTPUT: «5»
my @c = <a b>;
@c.append: $a.list, 7; # The array variable @c has 4 elements, because
# the list $a wasn't the only argument and thus
# wasn't flatten by the append operation
say @c.elems; # OUTPUT: «4»
my @d = <a b>;
@d.append: $a; # The array variable @d has 3 elements, because
# $a is in an item context and as far as append is
# concerned a single element
say @d.elems; # OUTPUT: «3»
The same flattening behavior applies all objects that do the Iterable role, notably Hashes:
my %h = a => 1, b => 2;
my @b = %h; say @b.elems; # OUTPUT: «2»
my @c = %h, ; say @c.elems; # OUTPUT: «1»
my @d = $%h; say @d.elems; # OUTPUT: «1»
Slurpy parameters (*@a
) flatten non-itemized sublists:
sub fe(*@flat) { @flat.elems }
say fe(<a b>, <d e>); # OUTPUT: «4»
say fe(<a b>, <d e>.item); # OUTPUT: «3»
The empty list is created with ()
. Smartmatching against the empty
list will check for the absence of elements.
my @a;
for @a, @a.list, @a.Seq -> \listoid {
say listoid ~~ ()
}
# OUTPUT: «TrueTrueTrue»
Retrieving values from an empty list will always return Nil:
say ()[33.rand]; # OUTPUT: «Nil»
Coercion to Bool also indicates if the List
got any elements.
my @a;
say [@a.elems, @a.Bool, ?@a]; # OUTPUT: «[0 False False]»
@a.push: 42;
say [@a.elems, @a.Bool, ?@a]; # OUTPUT: «[1 True True]»
say 'empty' unless @a; # no output
Methods
method ACCEPTS
multi method ACCEPTS(List:D: $topic)
If $topic
is an Iterable, returns True
or False
based
on whether the contents of the two Iterables match. A
Whatever element in the invocant matches anything in the
corresponding position of the $topic
Iterable. A
HyperWhatever matches any number of any elements,
including no elements:
say (1, 2, 3) ~~ (1, *, 3); # OUTPUT: «True»
say (1, 2, 3) ~~ (9, *, 5); # OUTPUT: «False»
say (1, 2, 3) ~~ ( **, 3); # OUTPUT: «True»
say (1, 2, 3) ~~ ( **, 5); # OUTPUT: «False»
say (1, 3) ~~ (1, **, 3); # OUTPUT: «True»
say (1, 2, 4, 5, 3) ~~ (1, **, 3); # OUTPUT: «True»
say (1, 2, 4, 5, 6) ~~ (1, **, 5); # OUTPUT: «False»
say (1, 2, 4, 5, 6) ~~ ( ** ); # OUTPUT: «True»
say () ~~ ( ** ); # OUTPUT: «True»
In addition, returns False
if either the invocant or $topic
is a lazy Iterable, unless $topic
is the same object
as the invocant, in which case True
is returned.
If $topic
is not an Iterable, returns the invocant if
the invocant has no elements or its first element is a Match
object (this behavior powers m:g//
smartmatch), or False
otherwise.
routine list
multi list(+list)
multi method list(List:D:)
The method just returns the invocant self. The subroutine
adheres to the single argument rule:
if called with a single argument that is a non-itemized
Iterable it returns a List
based on the argument's
iterator; otherwise it just returns the argument list.
For example:
my $tuple = (1, 2); # an itemized List
put $tuple.list.raku; # OUTPUT: «(1, 2)»
put list($tuple).raku; # OUTPUT: «($(1, 2),)»
put list(|$tuple).raku; # OUTPUT: «(1, 2)»
The last statement uses the prefix:<|> operator to flatten the tuple into an argument list, so it is equivalent to:
put list(1, 2).raku; # OUTPUT: «(1, 2)»
There are other ways to list the elements of an itemized single argument. For example, you can decontainerize|/routine/<> the argument or use the @ list contextualizer:
put list($tuple<>).raku; # OUTPUT: «(1, 2)»
put list(@$tuple).raku; # OUTPUT: «(1, 2)»
Note that converting a type object to a list may not do what you expect:
put List.list.raku; # OUTPUT: «(List,)»
This is because the .list
candidate accepting a type object as the invocant
is provided by Any. That candidate returns
a list with one element: the type object self. If you're developing a collection
type whose type object should be a valid representation of an empty collection,
you may want to provide your own candidate for undefined invocants or override
the Any:
candidates with an "only" method. For example:
my class LinkedList {
has $.value; # the value stored in this node
has LinkedList $.next; # undefined if there is no next node
method values( --> Seq:D) {
my $node := self;
gather while $node {
take $node.value;
$node := $node.next;
}
}
method list( --> List:D) {
self.values.list;
}
}
my LinkedList $nodes; # an empty linked list
put $nodes.list.raku; # OUTPUT: «()»
routine elems
sub elems($list --> Int:D)
method elems(List:D: --> Int:D)
Returns the number of elements in the list.
say (1,2,3,4).elems; # OUTPUT: «4»
routine end
sub end($list --> Int:D)
method end(List:D: --> Int:D)
Returns the index of the last element.
say (1,2,3,4).end; # OUTPUT: «3»
routine keys
sub keys($list --> Seq:D)
method keys(List:D: --> Seq:D)
Returns a sequence of indexes into the list (e.g.,
0...(@list.elems-1)
).
say (1,2,3,4).keys; # OUTPUT: «(0 1 2 3)»
routine values
sub values($list --> Seq:D)
method values(List:D: --> Seq:D)
Returns a sequence of the list elements, in order.
say (1,2,3,4).^name; # OUTPUT: «List»
say (1,2,3,4).values.^name; # OUTPUT: «Seq»
routine kv
sub kv($list --> Seq:D)
method kv(List:D: --> Seq:D)
Returns an interleaved sequence of indexes and values. For example
say <a b c>.kv; # OUTPUT: «(0 a 1 b 2 c)»
routine pairs
sub pairs($list --> Seq:D)
method pairs(List:D: --> Seq:D)
Returns a sequence of pairs, with the indexes as keys and the list values as values.
say <a b c>.pairs; # OUTPUT: «(0 => a 1 => b 2 => c)»
routine antipairs
method antipairs(List:D: --> Seq:D)
Returns a Seq of pairs, with the values as keys and the indexes as values, i.e. the direct opposite to pairs.
say <a b c>.antipairs; # OUTPUT: «(a => 0 b => 1 c => 2)»
routine invert
method invert(List:D: --> Seq:D)
Assumes every element of the List is a Pair. Returns all elements as a Seq of Pairs where the keys and values have been exchanged. If the value of a Pair is an Iterable, then it will expand the values of that Iterable into separate pairs.
my $l = List.new('a' => (2, 3), 'b' => 17);
say $l.invert; # OUTPUT: «(2 => a 3 => a 17 => b)»
routine join
sub join($separator, *@list)
method join(List:D: $separator = "")
Treats the elements of the list as strings by calling
.Str on each of them, interleaves them with
$separator
and concatenates everything into a single string.
Example:
say join ', ', <a b c>; # OUTPUT: «a, b, c»
The method form also allows you to omit the separator:
say <a b c>.join; # OUTPUT: «abc»
Note that the method form does not flatten sublists:
say (1, <a b c>).join('|'); # OUTPUT: «1|a b c»
The subroutine form behaves slurpily, flattening all arguments after the first into a single list:
say join '|', 1, <a b c>; # OUTPUT: «1|a|b|c»
In this case, the list <a b c>
is slurped and flattened, unlike what
happens when join
is invoked as a method.
If one of the elements of the list happens to be a Junction, then join
will also return a Junction with concatenation done as much as possible:
say ("a"|"b","c","d").join; # OUTPUT: «any(acd,bcd)»
routine map
multi method map(\SELF: &block)
multi map(&code, +values)
Examples applied to lists are included here for the purpose of illustration.
For a list, it invokes &code
for each element and gathers the return values
in a sequence and returns it. This happens lazily, i.e. &code
is only invoked
when the return values are accessed.Examples:
say ('hello', 1, 22/7, 42, 'world').map: { .^name } # OUTPUT: «(Str Int Rat Int Str)»
say map *.Str.chars, 'hello', 1, 22/7, 42, 'world'; # OUTPUT: «(5 1 8 2 5)»
map
inspects the arity of the code object, and tries to pass as many
arguments to it as expected:
sub b($a, $b) { "$a before $b" };
say <a b x y>.map(&b).join(', '); # OUTPUT: «a before b, x before y»
iterates the list two items at a time.
Note that map
does not flatten embedded lists and arrays, so
((1, 2), <a b>).map({ .join(',')})
passes (1, 2)
and <a b>
in turn to the block, leading to a total of
two iterations and the result sequence "1,2", "a,b"
.
If &code
is a Block loop phasers will be executed and
loop control statements will be treated as in loop control flow. Please
note that return
is executed in the context of its definition. It is
not the return statement of the block but the surrounding Routine. Using
a Routine will also handle loop control statements and
loop phasers. Any Routine specific control statement or phaser will
be handled in the context of that Routine.
sub s {
my &loop-block = {
return # return from sub s
};
say 'hi';
(1..3).map: &loop-block;
say 'oi‽' # dead code
};
s
# OUTPUT: «hi»
method flatmap
method flatmap(List:D: &code --> Seq:D)
Convenience method, analogous to .map(&block).flat.
method gist
multi method gist(List:D: --> Str:D)
Returns the string containing the parenthesized "gist" of the List,
listing up to the first 100 elements, separated by space, appending an
ellipsis if the List has more than 100 elements. If List
is-lazy, returns string '(...)'
put (1, 2, 3).gist; # OUTPUT: «(1 2 3)»
put (1..∞).List.gist; # OUTPUT: «(...)»
put (1..200).List.gist;
# OUTPUT:
# (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
# 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
# 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
# 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
# 96 97 98 99 100 ...)
routine grep
sub grep(Mu $matcher, *@elems, :$k, :$kv, :$p, :$v --> Seq:D)
method grep(List:D: Mu $matcher, :$k, :$kv, :$p, :$v --> Seq:D)
Returns a sequence of elements against which $matcher
smartmatches.
The elements are returned in the order in which they appear in the original
list.
Examples:
say ('hello', 1, 22/7, 42, 'world').grep: Int; # OUTPUT: «(1 42)»
say grep { .Str.chars > 3 }, 'hello', 1, 22/7, 42, 'world'; # OUTPUT: «(hello 3.142857 world)»
Note that if you want to grep for elements that do not match, you can
use a none
-Junction:
say <a b 6 d 8 0>.grep(none Int); # OUTPUT: «(a b d)»
say <a b c d e f>.grep(none /<[aeiou]>/); # OUTPUT: «(b c d f)»
Another option to grep for elements that do not match a regex is to use a block:
say <a b c d e f>.grep({! /<[aeiou]>/}) # OUTPUT: «(b c d f)»
The reason the example above works is because a regex in Boolean context applies
itself to $_
. In this case, !
boolifies the /<[aeiou]>/
regex and
negates the result. Smartmatching against a Callable (in this
case a Block) returns the value returned from that callable, so
the boolified result of a regex is then used to decide whether the current value
should be kept in the result of a grep.
The optional named parameters :k
, :kv
, :p
, :v
provide the same
functionality as on slices:
k
Only return the index values of the matching elements in order.
kv
Return both the index and matched elements in order.
p
Return the index and the matched element as a Pair, in order.
v
Only return the matched elements (same as not specifying any named parameter at all).
Examples:
say ('hello', 1, 22/7, 42, 'world').grep: Int, :k;
# OUTPUT: «(1 3)»
say grep { .Str.chars > 3 }, :kv, 'hello', 1, 22/7, 42, 'world';
# OUTPUT: «(0 hello 2 3.142857 4 world)»
say grep { .Str.chars > 3 }, :p, 'hello', 1, 22/7, 42, 'world';
# OUTPUT: «(0 => hello 2 => 3.142857 4 => world)»
routine first
sub first(Mu $matcher, *@elems, :$k, :$kv, :$p, :$end)
method first(List:D: Mu $matcher?, :$k, :$kv, :$p, :$end)
Returns the first item of the list which smartmatches against $matcher
,
returns Nil when no values match. The optional named parameter :end
indicates that the search should be from the end of the list, rather than
from the start.
Examples:
say (1, 22/7, 42, 300).first: * > 5; # OUTPUT: «42»
say (1, 22/7, 42, 300).first: * > 5, :end; # OUTPUT: «300»
say ('hello', 1, 22/7, 42, 'world').first: Complex; # OUTPUT: «Nil»
The optional named parameters :k
, :kv
, :p
provide the same
functionality as on slices:
k
Return the index value of the matching element. Index is always counted from
the beginning of the list, regardless of whether the :end
named parameter
is specified or not.
kv
Return both the index and matched element.
p
Return the index and the matched element as a Pair.
Examples:
say (1, 22/7, 42, 300).first: * > 5, :k; # OUTPUT: «2»
say (1, 22/7, 42, 300).first: * > 5, :p; # OUTPUT: «2 => 42»
say (1, 22/7, 42, 300).first: * > 5, :kv, :end; # OUTPUT: «(3 300)»
In method form, the $matcher
can be omitted, in which case the first
available item (or last if :end
is set) will be returned. See also
head and tail methods.
method head
multi method head(Any:D:) is raw
multi method head(Any:D: Callable:D $w)
multi method head(Any:D: $n)
This method is directly inherited from Any, and it returns the first $n
items of the list, an empty list if $n
<= 0, or the first element with no
argument. The version that takes a Callable uses a WhateverCode to specify
all elements, starting from the first, but the last ones.
Examples:
say <a b c d e>.head ; # OUTPUT: «a»
say <a b c d e>.head(2); # OUTPUT: «(a b)»
say <a b c d e>.head(*-3); # OUTPUT: «(a b)»
method tail
multi method tail(List:D:)
multi method tail(List:D: $n --> Seq:D)
Returns a Seq containing the last $n
items of the list.
Returns an empty Seq if $n
<= 0. Defaults to the last element if
no argument is specified. Throws an exception if the list is lazy.
Examples:
say <a b c d e>.tail(*-3);# OUTPUT: «(d e)»
say <a b c d e>.tail(2); # OUTPUT: «(d e)»
say <a b c d e>.tail; # OUTPUT: «e»
In the first case, $n
is taking the shape of a WhateverCode to indicate
the number of elements from the beginning that will be excluded. $n
can be
either a Callable, in which case it will be called with the value 0
, or
anything else that can be converted to a number, in which case it will use
that as the number of elements in the output Seq.
say <a b c d e>.tail( { $_ - 2 } ); # OUTPUT: «(c d e)»
routine categorize
multi method categorize()
multi method categorize(Whatever)
multi method categorize($test, :$into!, :&as)
multi method categorize($test, :&as)
multi categorize($test, +items, :$into!, *%named )
multi categorize($test, +items, *%named )
These methods are directly inherited from Any; see Any.list for more examples.
This routine transforms a list of values into a hash representing the
categorizations of those values according to $test
, which is called once for
every element in the list; each hash key represents one possible categorization
for one or more of the incoming list values, and the corresponding hash value
contains an array of those list values categorized by the $test
, acting like
a mapper, into the category of the associated key.
Note that, unlike classify, which assumes that the return
value of the mapper is a single value, categorize
always assumes that the
return value of the mapper is a list of categories that are appropriate to the
current value.
Example:
sub mapper(Int $i) returns List {
$i %% 2 ?? 'even' !! 'odd',
$i.is-prime ?? 'prime' !! 'not prime'
}
say categorize &mapper, (1, 7, 6, 3, 2);
# OUTPUT: «{even => [6 2], not prime => [1 6], odd => [1 7 3], prime => [7 3 2]}»
routine classify
multi method classify($test, :$into!, :&as)
multi method classify($test, :&as)
multi classify($test, +items, :$into!, *%named )
multi classify($test, +items, *%named )
Transforms a list of values into a hash representing the classification
of those values; each hash key represents the classification for one or
more of the incoming list values, and the corresponding hash value
contains an array of those list values classified into the category of
the associated key. $test
will be an expression that will produce the
hash keys according to which the elements are going to be classified.
Example:
say classify { $_ %% 2 ?? 'even' !! 'odd' }, (1, 7, 6, 3, 2);
# OUTPUT: «{even => [6 2], odd => [1 7 3]}»
say ('hello', 1, 22/7, 42, 'world').classify: { .Str.chars };
# OUTPUT: «{1 => [1], 2 => [42], 5 => [hello world], 8 => [3.142857]}»
It can also take :as
as a named parameter, transforming the value
before classifying it:
say <Innie Minnie Moe>.classify( { $_.chars }, :as{ lc $_ });
# OUTPUT: «{3 => [moe], 5 => [innie], 6 => [minnie]}»
This code is classifying by number of characters, which is the
expression that has been passed as $test
parameter, but the :as
block lowercases it before doing the transformation. The named parameter
:into
can also be used to classify into a newly defined variable:
<Innie Minnie Moe>.classify( { $_.chars }, :as{ lc $_ }, :into( my %words{Int} ) );
say %words; # OUTPUT: «{3 => [moe], 5 => [innie], 6 => [minnie]}»
We are declaring the scope of %words{Int}
on the fly, with keys that
are actually integers; it gets created with the result of the
classification.
method Bool
method Bool(List:D: --> Bool:D)
Returns True
if the list has at least one element, and False
for the empty list.
say ().Bool; # OUTPUT: «False»
say (1).Bool; # OUTPUT: «True»
method Str
method Str(List:D: --> Str:D)
Stringifies the elements of the list and joins them with spaces
(same as .join(' ')
).
say (1,2,3,4,5).Str; # OUTPUT: «1 2 3 4 5»
method Int
method Int(List:D: --> Int:D)
Returns the number of elements in the list (same as .elems
).
say (1,2,3,4,5).Int; # OUTPUT: «5»
method Numeric
method Numeric(List:D: --> Int:D)
Returns the number of elements in the list (same as .elems
).
say (1,2,3,4,5).Numeric; # OUTPUT: «5»
method Capture
method Capture(List:D: --> Capture:D)
Returns a Capture where each Pair, if any, in the
<List
has been converted to a named argument (with the
key of the Pair stringified). All other
elements in the List
are converted to positional arguments in the order they
are found, i.e. the first non pair item in the list becomes the first positional
argument, which gets index 0
, the second non pair item becomes the second
positional argument, getting index 1
etc.
my $list = (7, 5, a => 2, b => 17);
my $capture = $list.Capture;
say $capture.keys; # OUTPUT: «(0 1 a b)»
my-sub(|$capture); # OUTPUT: «7, 5, 2, 17»
sub my-sub($first, $second, :$a, :$b) {
say "$first, $second, $a, $b"
}
A more advanced example demonstrating the returned Capture being matched against a Signature.
my $list = (7, 5, a => 2, b => 17);
say so $list.Capture ~~ :($ where * == 7,$,:$a,:$b); # OUTPUT: «True»
$list = (8, 5, a => 2, b => 17);
say so $list.Capture ~~ :($ where * == 7,$,:$a,:$b); # OUTPUT: «False»
routine pick
multi pick($count, *@list --> Seq:D)
multi method pick(List:D: $count --> Seq:D)
multi method pick(List:D: --> Mu)
multi method pick(List:D: Callable $calculate --> Seq:D)
If $count
is supplied: Returns $count
elements chosen at random
and without repetition from the invocant. If *
is passed as $count
,
or $count
is greater than or equal to the size of the list, then all
elements from the invocant list are returned in a random sequence; i.e. they
are returned shuffled.
In method form, if $count
is omitted: Returns a single random item from
the list, or Nil if the list is empty
Examples:
say <a b c d e>.pick; # OUTPUT: «b»
say <a b c d e>.pick: 3; # OUTPUT: «(c a e)»
say <a b c d e>.pick: *; # OUTPUT: «(e d a b c)»
As of the 2021.06 release of the Rakudo compiler, it is also possible to
specify **
(aka HyperWhatever) as the count.
In that case, .pick
will start picking again on the original list
after it has been exhausted, again and again, indefinitely.
say <a b c>.pick(**).head(10); # OUTPUT: «((a c b c a b b c a b))»
routine roll
multi roll($count, *@list --> Seq:D)
multi method roll(List:D: $count --> Seq:D)
multi method roll(List:D: --> Mu)
If $count
is supplied: Returns a sequence of $count
elements, each
randomly selected from the list. Each random choice is made independently, like
a separate die roll where each die face is a list element. If *
is passed as
$count
returns a lazy, infinite sequence of randomly chosen elements from the
original list.
If $count
is omitted: Returns a single random item from the list, or
Nil if the list is empty
Examples:
say <a b c d e>.roll; # 1 random letter
say <a b c d e>.roll: 3; # 3 random letters
say roll 8, <a b c d e>; # 8 random letters
my $random-digits := (^10).roll(*);
say $random-digits[^15]; # 15 random digits
routine eager
multi method eager(List:D: --> List:D)
Evaluates all elements in the List
eagerly, and returns them as a List
.
my \ll = (lazy 1..5).cache;
say ll[]; # OUTPUT: «(...)»
say ll.eager # OUTPUT: «(1 2 3 4 5)»
routine reverse
multi reverse(*@list --> Seq:D)
multi method reverse(List:D: --> Seq:D)
Returns a Seq with the same elements in reverse order.
Note that reverse
always refers to reversing elements of a list;
to reverse the characters in a string, use flip.
Examples:
say <hello world!>.reverse; # OUTPUT: «(world! hello)»
say reverse ^10; # OUTPUT: «(9 8 7 6 5 4 3 2 1 0)»
routine rotate
multi rotate(@list, Int:D $n = 1 --> Seq:D)
multi method rotate(List:D: Int:D $n = 1 --> Seq:D)
Returns a Seq with the list elements rotated to the left
when $n
is positive or to the right otherwise.
Examples:
say <a b c d e>.rotate(2); # OUTPUT: (c d e a b)
say <a b c d e>.rotate(-1); # OUTPUT: (e a b c d)
Note: Before Rakudo version 2020.06 a new List
was returned instead
of a Seq.
routine sort
multi sort(*@elems --> Seq:D)
multi sort(&custom-routine-to-use, *@elems --> Seq:D)
multi method sort(List:D: --> Seq:D)
multi method sort(List:D: &custom-routine-to-use --> Seq:D)
Sorts the list, smallest element first. By default infix:<cmp> is used for comparing list elements.
If &custom-routine-to-use
is provided, and it accepts two arguments,
it is invoked for pairs of list elements, and should return
Order::Less
, Order::Same
or Order::More
.
If &custom-routine-to-use
accepts only one argument, the list
elements are sorted according to <custom-routine-to-use($a) cmp
custom-routine-to-use($b)>
. The return values of
&custom-routine-to-use
are cached, so that &custom-routine-to-use
is only called once per list element.
Examples:
say (3, -4, 7, -1, 2, 0).sort; # OUTPUT: «(-4 -1 0 2 3 7)»
say (3, -4, 7, -1, 2, 0).sort: *.abs; # OUTPUT: «(0 -1 2 3 -4 7)»
say (3, -4, 7, -1, 2, 0).sort: { $^b leg $^a }; # OUTPUT: «(7 3 2 0 -4 -1)»
Additionally, if &custom-routine-to-use
returns a List
, elements
will be sorted based upon multiple values with subsequent values in the
List
being used to break the tie if the comparison between the prior
elements evaluate to Order::Same
.
my @resistance = (
%( first-name => 'Kyle', last-name => 'Reese' ),
%( first-name => 'Sarah', last-name => 'Connor' ),
%( first-name => 'John', last-name => 'Connor' ),
);
.say for @resistance.sort: { .<last-name>, .<first-name> };
#`(
OUTPUT:
{first-name => John, last-name => Connor}
{first-name => Sarah, last-name => Connor}
{first-name => Kyle, last-name => Reese}
)
This sorting can be based on characteristics of a single element:
say <ddd aaa bbb bb ccc c>.sort( {.chars, .Str} );
# OUTPUT: «(c bb aaa bbb ccc ddd)»
In this case, elements of the array are sorted in ascending order
according first to the string length (.chars
) and second to the
actual alphabetical order .Str
) if the length is exactly the same.
Any number of criteria can be used in this:
say <01 11 111 2 20 02>.sort( { .Int, .comb.sum, .Str } );
# OUTPUT: «(01 02 2 11 20 111)»
Calling the sort
sub without any arguments has become a runtime error as of
release 2022.07 of the Rakudo compiler:
sort; # ERROR: «Must specify something to sort»
As of release 2023.08 of the Rakudo compiler it is also possible to specify
a :k
named argument. This will cause the result to be a list of
indices of the sorting process.
say <a c b d e>.sort(:k); # OUTPUT: «(0 2 1 3 4)»
say sort <a c b d e>, :k; # OUTPUT: «(0 2 1 3 4)»
routine reduce
multi method reduce(Any:D: &with)
multi reduce (&with, +list)
Returns a single "combined" value from a list of arbitrarily many values, by
iteratively applying a routine which knows how to combine two values. In
addition to the subroutine and the list, an initial value can be provided to
initialize the reduction, which ends up being the return value if the list is
empty. Thus reduce f, init, list
combines the elements of the list from left
to right, as is shown in the following pseudocode:
result0 = init
result1 = f(result0, list[0])
result2 = f(result1, list[1])
...
resultn = f(resultn-1, list[n-1])
resultn
is the final result for an n-element list.
say reduce &infix:<+>, (1, 2, 3); # OUTPUT: «6»
say (1, 2, 3).reduce: &infix:<+>; # OUTPUT: «6»
say reduce &max, (5, 9, 12, 1); # OUTPUT: «12»
If list
contains just a single element, the operator is applied to that
single element if possible; if not, it returns the element itself.
say reduce &infix:<->, (10,); # OUTPUT: «10»
When the list contains no elements, an exception is thrown, unless &with
is an operator with a known identity value (e.g., the identity value of
infix:<+>
is 0). For this reason, you're advised to prefix the input list
with an initial value (or explicit identity value):
my \strings = "One good string!", "And one another good string!";
say reduce { $^a ~ $^b }, '', |strings; # like strings.join
my \numbers = 1, 2, 3, 4, 5;
say reduce { $^a > $^b ?? $^a !! $^b }, 0, |numbers; # like numbers.max
sub count-and-sum-evens( (Int \count, Int \sum), Int \x ) {
x %% 2 ?? (count+1, sum+x) !! (count, sum)
}
say reduce &count-and-sum-evens, (0, 0), |numbers; # OUTPUT: «(2 6)»
In the last example, since reduce
only supports one initial value we use a
List
with two values, which is by itself a single value. The
count-and-sum-evens
subroutine takes two positional values: a
List
of two Ints and an Int, and return a List
storing the count
and sum of the even integers accumulated.
If &with
is the code object of an operator, its
inherent identity value and associativity is respected - in other words,
(VAL1, VAL2, VAL3).reduce(&infix:<OP>)
is the same as VAL1 OP VAL2 OP VAL3
even for operators which aren't left-associative:
# Raise 2 to the 81st power, because 3 to the 4th power is 81
(2,3,4).reduce(&infix:<**>).lsb.say; # OUTPUT: «81»
(2**(3**4)).lsb.say; # OUTPUT: «81»
(2**3**4).lsb.say; # OUTPUT: «81»
# Subtract 4 from -1, because 2 minus 3 is -1
(2,3,4).reduce(&infix:<->).say; # OUTPUT: «-5»
((2-3)-4).say; # OUTPUT: «-5»
(2-3-4).say; # OUTPUT: «-5»
Since reducing with an infix operator is a common thing to do, the
reduction metaoperator [ ]
provides a syntactic shortcut. Thus, instead of passing the operator's code
object to reduce
, just pass the operator directly to [ ]
. To use a
user-defined subroutine instead, provide an additional layer of square brackets
around the subroutine's code object:
say [*] (1, 2, 3, 4); # OUTPUT: «24»
say [min] (4, 2, 1, 3); # OUTPUT: «1»
sub mult { $^a * $^b };
say [[&mult]] (1, 2, 3, 4); # OUTPUT: «24»
Semantically, all the following do the same thing:
my \numbers = 1, 2, 3, 4, 5;
say reduce { $^a + $^b }, 0, |numbers;
say reduce * + *, 0, |numbers;
say reduce &[+], numbers; # operator does not need explicit identity value
say [+] numbers;
Since reduce
is an implicit loop that iterates over with its reducing subroutine,
it responds to next
, last
and redo
statements inside &with
:
sub last-after-seven { last if $^a > 7; $^a + $^b };
say (2, 3, 4, 5).reduce: &last-after-seven; # OUTPUT: «9»
Whether reduce
accumulates the elements starting from the left or from the right
depends on the operator. In the functional programming world, this operation is
generally called a fold.
With a right-associative operator it is a right fold, otherwise (and usually)
it is a left fold. In Raku, you can specify the associativity of an operator
with the is assoc trait.
sub infix:<foo>($a, $b) is assoc<right> { "($a, $b)" }
say [foo] 1, 2, 3, 4; # OUTPUT: «(1, (2, (3, 4)))»
sub infix:<bar>($a, $b) is assoc<left> { "($a, $b)" }
say [bar] 1, 2, 3, 4; # OUTPUT: «(((1, 2), 3), 4)»
Practical example 1: In this example, we generate a random-ish math
formula (e.g., "(4 + ((3 * x) + 11) / 6))") using reduce
.
my @ops = [Z] (<+ - * />, 1..20)».roll(4);
say ('x', |@ops).reduce: -> $formula, [$op, $number] {
Bool.pick ?? "($formula $op $number)"
!! "($number $op $formula)"
}
Practical example 2: Suppose we have a polynomial represented as a list of
integer coefficients, c[n-1], c[n-2], ..., c[0], where c[i] is the coefficient
of xi. We can evaluate it using map
and reduce
as follows:
sub evaluate(List:D \c where c.all ~~ Int, Rat:D \x --> Rat:D) {
my \xi = (c.elems ^... 0).map: -> \i { x ** i }; # [x^(n-1), ..., x^0]
my \axi = [+] c Z* xi; # [c[n-1]*x^(n-1), ..., c[*]x^0]
[+] axi; # sum of axi
}
my \c = 2, 3, 1; # 2x² + 3x + 1
say evaluate c, 3.0; # OUTPUT: «28»
say evaluate c, 10.0; # OUTPUT: «231»
routine produce
multi produce(&with, *@values)
multi method produce(List:D: &with)
Generates a list of all intermediate "combined" values along with the final result by iteratively applying a function which knows how to combine two values.
If @values
contains just a single element, a list containing that element
is returned immediately. If it contains no elements, an exception is thrown,
unless &with
is an operator with a known identity value.
If &with
is the function object of an operator, its
inherent identity value and associativity is respected - in other words,
(VAL1, VAL2, VAL3).produce(&[OP])
is the same as VAL1 OP VAL2 OP VAL3
even
for operators which aren't left-associative:
# Raise 2 to the 81st power, because 3 to the 4th power is 81
[2,3,4].produce(&[**]).say; # OUTPUT: «(4 81 2417851639229258349412352)»
say produce &[**], (2,3,4); # OUTPUT: «(4 81 2417851639229258349412352)»
say [\**] (2,3,4); # OUTPUT: «(4 81 2417851639229258349412352)»
# Subtract 4 from -1, because 2 minus 3 is -1
[2,3,4].produce(&[-]).say; # OUTPUT: «(2 -1 -5)»
say produce &[-], (2,3,4); # OUTPUT: «(2 -1 -5)»
say [\-] (2,3,4); # OUTPUT: «(2 -1 -5)»
A triangle metaoperator [\ ]
provides a syntactic shortcut for
producing with an infix operator:
# The following all do the same thing...
my @numbers = (1,2,3,4,5);
say produce { $^a + $^b }, @numbers;
say produce * + *, @numbers;
say produce &[+], @numbers; # operator does not need explicit identity
say [\+] @numbers; # most people write it this way
The visual picture of a triangle [\
is not accidental. To produce a
triangular list of lists, you can use a "triangular comma":
[\,] 1..5;
# (
# (1)
# (1 2)
# (1 2 3)
# (1 2 3 4)
# (1 2 3 4 5)
# )
Since produce
is an implicit loop, it responds to next
, last
and
redo
statements inside &with
:
say (2,3,4,5).produce: { last if $^a > 7; $^a + $^b }; # OUTPUT: «(2 5 9)»
routine combinations
multi combinations($from, $of = 0..* --> Seq:D)
multi method combinations(List:D: Int() $of --> Seq:D)
multi method combinations(List:D: Iterable:D $of = 0..* --> Seq:D)
Returns a Seq with all $of
-combinations of the invocant list.
$of
can be a numeric Range, in which case combinations of the
range of item numbers it represents will be returned (i.e. 2.6 .. 4
will
return 2-, 3-, and 4-item combinations). Otherwise, $of
is coerced to an
Int.
.say for <a b c>.combinations: 2;
# OUTPUT:
# (a b)
# (a c)
# (b c)
Above, there are three possible ways to combine the 2-items lists from the original list, which is what we receive in the output. See permutations if you want permutations instead of combinations.
With Range argument, we get both three 2-item combinations and one 3-item combination:
.say for <a b c>.combinations: 2..3;
# OUTPUT:
# (a b)
# (a c)
# (b c)
# (a b c)
If $of
is negative or is larger than there are items in the given list, an
empty list will be returned. If $of
is zero, a 1-item list containing an
empty list will be returned (there's exactly 1 way to pick no items).
The subroutine form is equivalent to the method form called on the first
argument ($from
), with the exception that if $from
is not an
Iterable, it gets coerced to an Int and combinations are
made from a Range constructed with 0..^$from
instead:
.say for combinations 3, 2
# OUTPUT:
# (0 1)
# (0 2)
# (1 2)
Note: some implementations may limit the maximum value of
non-Iterable $from
. On Rakudo, 64-bit systems have a limit
of 2³¹-1
and 32-bit systems have a limit of 2²⁸-1
.
routine permutations
multi permutations(Int() $from --> Seq:D)
multi permutations(Iterable $from --> Seq:D)
multi method permutations(List:D: --> Seq:D)
Returns all possible permutations of a list as a Seq of lists:
.say for <a b c>.permutations;
# OUTPUT:
# (a b c)
# (a c b)
# (b a c)
# (b c a)
# (c a b)
# (c b a)
permutations
treats all elements as unique, thus (1, 1, 2).permutations
returns a list of 6 elements, even though there are only three distinct
permutations, due to first two elements being the same.
The subroutine form behaves the same as the method form, computing permutations
from its first argument $from
. If $from
is not an
Iterable, coerces $from
to an Int and picks from a
Range constructed with 0..^$from
:
.say for permutations 3;
# OUTPUT:
# (0 1 2)
# (0 2 1)
# (1 0 2)
# (1 2 0)
# (2 0 1)
# (2 1 0)
routine rotor
method rotor(*@cycle, Bool() :$partial --> Seq:D)
Returns a sequence of lists, where each sublist is made up of elements of the invocant.
In the simplest case, @cycle
contains just one integer, in which case the
invocant list is split into sublists with as many elements as the integer
specifies. If :$partial
is True, the final chunk is included even if it
doesn't satisfy the length requirement:
say ('a'..'h').rotor(3).join('|'); # OUTPUT: «a b c|d e f»
say ('a'..'h').rotor(3, :partial).join('|'); # OUTPUT: «a b c|d e f|g h»
If the element of @cycle
is a Pair instead, the key of the
pair specifies the length of the return sublist, and the value the gap between
sublists; negative gaps produce overlap:
say ('a'..'h').rotor(2 => 1).join('|'); # OUTPUT: «a b|d e|g h»
say ('a'..'h').rotor(3 => -1).join('|'); # OUTPUT: «a b c|c d e|e f g»
If @cycle
contains more than element, rotor
cycles through it to find
the number of elements for each sublist:
say ('a'..'h').rotor(2, 3).join('|'); # OUTPUT: «a b|c d e|f g»
say ('a'..'h').rotor(1 => 1, 3).join('|'); # OUTPUT: «a|c d e|f»
Combining multiple cycles and :partial
also works:
say ('a'..'h').rotor(1 => 1, 3 => -1, :partial).join('|');
# OUTPUT: «a|c d e|e|g h»
See this blog post for more elaboration on rotor.
multi rotor(Int:D $batch, \source, Bool() :$partial --> Seq:D)
multi rotor(*@cycle, \source, Bool() :$partial --> Seq:D)
Available as of 6.e language version (early implementation exists in Rakudo compiler 2022.02+).
say rotor(3, 'a'..'h').join('|'); # OUTPUT: «a b c|d e f»
say rotor(3, 'a'..'h', :partial).join('|'); # OUTPUT: «a b c|d e f|g h»
say rotor(2 => 1, 'a'..'h').join('|'); # OUTPUT: «a b|d e|g h»
say rotor(3 => -1, 'a'..'h').join('|'); # OUTPUT: «a b c|c d e|e f g»
say rotor(1 => 1, 3 => -1, 'a'..'h', :partial).join('|');
# OUTPUT: «a|c d e|e|g h»
method batch
multi method batch(Int:D $batch --> Seq)
multi method batch(Int:D :$elems --> Seq)
Returns a sequence of lists, wherein each list with the exception of the last
one is guaranteed to comprise a number of elements equal to the batch size
specified by $batch
or $elems
, respectively. If the invocant has a number
of elements that is not an integer multiple of the batch size, the last list in
the returned sequence will contain any remaining elements and thus have less
than $batch
or $elems
elements. Accordingly, .batch($batch)
is
shorthand for .rotor($batch, :partial)
.
routine cross
sub cross(+@e, :&with --> Seq:D)
Computes the cross-product of two or more lists or Iterables. This returns a sequence of lists where the first item in each list is an item from the first iterable, the second is from the second given iterable, etc. Every item will be paired with every other item in all the other lists.
say cross(<a b c>, <d e f>).map(*.join).join(",")
# OUTPUT: «ad,ae,af,bd,be,bf,cd,ce,cf»
The cross
routine has an infix synonym as well, named X.
say (<a b c> X <d e f>).map(*.join).join(",")
# output is the same as the previous example
If the optional with
parameter is passed, it is used as a reduction operation
to apply to each of the cross product items.
say cross([1, 2, 3], [4, 5, 6], :with(&infix:<*>)).join(",");
# OUTPUT: «4,5,6,8,10,12,12,15,18»
The X
operator can be combined with another operator as a
metaoperator to perform a reduction as well:
say ([1, 2, 3] X* [4, 5, 6]).join(",")
# same output as the previous example
routine zip
sub zip(+@e, :&with --> Seq:D)
Builds a 'list of lists', returned as a sequence, from multiple input lists or other Iterables.
zip
iterates through each of the input lists synchronously, 'Zipping' them
together, so that elements are grouped according to their input list index, in
the order that the lists are provided.
say zip(<a b c>, <d e f>, <g h i>);
# OUTPUT: «((a d g) (b e h) (c f i))»
zip
has an infix synonym, the Z operator.
say <a b c> Z <d e f> Z <g h i>; # same output
zip
can provide input to a for loop :
for <a b c> Z <d e f> Z <g h i> -> [$x,$y,$z] {say ($x,$y,$z).join(",")}
# OUTPUT: «a,d,gb,e,hc,f,i»
, or more succinctly:
say .join(",") for zip <a b c>, <d e f>, <g h i>; # same output
Note, that if the input lists have an unequal number of elements, then
zip
terminates once the shortest input list is exhausted, and trailing
elements from longer input lists are discarded.
say <a b c> Z <d e f m n o p> Z <g h i>;
# ((a d g) (b e h) (c f i))
In cases where data clipping is possible, but undesired, then consider using
roundrobin instead of zip
.
The optional with
parameter will additionally reduce the zipped lists. For
example, the following multiplies corresponding elements together to return a
single list of products.
.say for zip <1 2 3>, [1, 2, 3], (1, 2, 3), :with(&infix:<*>);
# OUTPUT: «1827»
The Z
form can also be used to perform reduction by implicitly
setting the with
parameter with a metaoperator :
.say for <1 2 3> Z* [1, 2, 3] Z* (1, 2, 3); # same output
routine roundrobin
sub roundrobin(+list-of-lists --> Seq)
Builds a 'list of lists', returned as a sequence, from multiple input lists or
other Iterables. roundrobin
returns an identical result to
that of zip, except when the input lists are allowed
to have an unequal number of elements.
say roundrobin <a b c>, <d e f>, <g h i>;
# OUTPUT: «((a d g) (b e h) (c f i))»
say .join(",") for roundrobin([1, 2], [2, 3], [3, 4]);
# OUTPUT: «1,2,32,3,4»
roundrobin
does not terminate once one or more of the input lists become
exhausted, but proceeds until all elements from all lists have been processed.
say roundrobin <a b c>, <d e f m n o p>, <g h i j>;
# OUTPUT: «((a d g) (b e h) (c f i) (m j) (n) (o) (p))»
say .join(",") for roundrobin([1, 2], [2, 3, 57, 77], [3, 4, 102]);
# OUTPUT: «1,2,32,3,457,10277»
Therefore no data values are lost due in the 'zipping' operation. A record of which input list provided which element cannot be gleaned from the resulting sequence, however.
roundrobin
can be useful in combining messy data to the point where a manual
post-processing step can then be undertaken.
sub roundrobin(+list-of-lists, :$slip --> Seq)
As of release 2022.02 of the Rakudo compiler, it is also possible to specify
a :slip
named argument. If specified with a true value, will
slip the produced values.
say roundrobin <a b c>, <d e f m n o p>, <g h i j>, :slip;
# OUTPUT: «(a d g b e h c f i m j n o p)»
routine sum
sub sum($list )
method sum(List:D:)
Returns the sum of all elements in the list or 0 if the list is empty. Throws an exception if an element can not be coerced into Numeric.
say (1, 3, pi).sum; # OUTPUT: «7.14159265358979»
say (1, "0xff").sum; # OUTPUT: «256»
say sum(0b1111, 5); # OUTPUT: «20»
If the list includes a Junction, the result will accordingly be a Junction:
say ( 1|2, 3).sum; # OUTPUT: «any(4, 5)»
When called on native integer arrays, it is also possible to specify
a :wrap
named parameter. This will add the values as native integers,
wrapping around if they exceed the size of a native integer. If you are
sure you will not exceed that value, or if you don't mind, using :wrap
will make the calculation about 20x as fast.
my int @a = ^1_000_000;
say @a.sum(:wrap); # OUTPUT: «499999500000»
method fmt
method fmt($format = '%s', $separator = ' ' --> Str:D)
Returns a string where each element in the list has been formatted according
to $format
and where each element is separated by $separator
. If the
list contains nested sub-lists, then fmt
will flatten them before
formatting each element. Thus, fmt
will treat [1, 2, [3, 4]]
as a list
with 4 elements rather than 3.
For more information about formats strings, see sprintf.
my @a = 8..11;
say @a.fmt('%03d', ','); # OUTPUT: «008,009,010,011»
method from
Assumes the list contains Match objects and returns the
value of .from
called on the first element of the list.
'abcdefg' ~~ /(c)(d)/;
say $/.list.from; # OUTPUT: «2»
"abc123def" ~~ m:g/\d/;
say $/.list.from; # OUTPUT: «3»
method to
"abc123def" ~~ m:g/\d/;
say $/.to; # OUTPUT: «6»
Assumes the List
contains Matches, such as the
$/
variable being a List
, when using :g
modifier in regexes. Returns the
value of .to
called on the last element of the list.
method sink
method sink(--> Nil) { }
It does nothing, and returns Nil, as the definition clearly shows.
sink [1,2,Failure.new("boo!"),"still here"]; # OUTPUT: «»
method Set
In general, creates a set which has as members elements of the list.
say <æ ß þ €>.Set; # OUTPUT: «Set(ß æ þ €)»
However, there might be some unexpected changes in case the list includes non-scalar data structures. For instance, with Pairs:
my @a = (:42a, :33b);
say @a; # OUTPUT: «[a => 42 b => 33]»
say @a.Set; # OUTPUT: «Set(a b)»
The set will be composed of the key
s of the Pair whose corresponding value
is not 0, eliminating all the values. Please check the
Set documentation for more examples and a
more thorough explanation.
Operators
infix cmp
multi infix:<cmp>(List @a, List @b)
Evaluates Lists
by comparing element @a[$i]
with @b[$i]
(for some
Int $i
, beginning at 0) and returning Order::Less
, Order::Same
, or
Order::More
depending on if and how the values differ. If the operation
evaluates to Order::Same
, @a[$i + 1]
is compared with @b[$i + 1]
. This
is repeated until one is greater than the other or all elements are exhausted.
If the List
s are of different lengths, at most only $n
comparisons will be
made (where $n = @a.elems min @b.elems
). If all of those comparisons evaluate
to Order::Same
, the final value is selected based upon which List
is
longer.
say (1, 2, 3) cmp (1, 2, 3); # OUTPUT: «Same»
say (4, 5, 6) cmp (4, 5, 7); # OUTPUT: «Less»
say (7, 8, 9) cmp (7, 8, 8); # OUTPUT: «More»
say (1, 2) cmp (1, 2, 3); # OUTPUT: «Less»
say (1, 2, 3) cmp (1, 2); # OUTPUT: «More»
say (9).List cmp (^10).List; # OUTPUT: «More»