my 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 = 'z';my = (, $, 'b');say [0].VAR.^name; # OUTPUT: «Scalar», containerizedsay [1].VAR.^name; # OUTPUT: «Scalar», containerizedsay [2].VAR.^name; # OUTPUT: «Str», non-containerized[0] = 'a'; # OK![1] = 'c'; # OK![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 = (1, 2, 3);for # one iterationfor .list # three iterationsmy = [1, 2, 3];for # one iterationfor .list # three iterationsmy = 1, 2, 3;for # three iterationsfor .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 = (1, 2, 3);my = (, ); # two elementsmy = .map(); # six elements, with explicit Slipmy = <a b>;.append: .list; # The array variable @b has 5 elements, because# the list $a is the sole argument to appendsay .elems; # OUTPUT: «5»my = <a b>;.append: .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 operationsay .elems; # OUTPUT: «4»my = <a b>;.append: ; # The array variable @d has 3 elements, because# $a is in an item context and as far as append is# concerned a single elementsay .elems; # OUTPUT: «3»
The same flattening behavior applies all objects that do the Iterable
role, notably Hash
es:
my = a => 1, b => 2;my = ; say .elems; # OUTPUT: «2»my = , ; say .elems; # OUTPUT: «1»my = $; say .elems; # OUTPUT: «1»
Slurpy parameters (*@a
) flatten non-itemized sublists:
sub fe(*)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 ;for , .list, .Seq -> \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 ;say [.elems, .Bool, ?]; # OUTPUT: «[0 False False]».push: 42;say [.elems, .Bool, ?]; # OUTPUT: «[1 True True]»say 'empty' unless ; # no output
Methods§
method ACCEPTS§
multi method ACCEPTS(List: )
If $topic
is an Iterable
, returns True
or False
based on whether the contents of the two Iterable
s 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:)
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 = (1, 2); # an itemized Listput .list.raku; # OUTPUT: «(1, 2)»put list().raku; # OUTPUT: «($(1, 2),)»put list(|).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 the argument or use the @
list contextualizer:
put list(<>).raku; # OUTPUT: «(1, 2)»put list(@).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:
mymy LinkedList ; # an empty linked listput .list.raku; # OUTPUT: «()»
routine elems§
sub elems( --> Int)method elems(List: --> Int)
Returns the number of elements in the list.
say (1,2,3,4).elems; # OUTPUT: «4»
routine end§
sub end( --> Int)method end(List: --> Int)
Returns the index of the last element.
say (1,2,3,4).end; # OUTPUT: «3»
routine keys§
sub keys( --> Seq)method keys(List: --> Seq)
Returns a sequence of indexes into the list (e.g., 0..(@list.elems-1)
).
say (1,2,3,4).keys; # OUTPUT: «0..3»
routine values§
sub values( --> Seq)method values(List: --> Seq)
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( --> Seq)method kv(List: --> Seq)
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( --> Seq)method pairs(List: --> Seq)
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: --> Seq)
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: --> Seq)
Assumes every element of the List is a Pair
. Returns all elements as a Seq
of Pair
s 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 = List.new('a' => (2, 3), 'b' => 17);say .invert; # OUTPUT: «(2 => a 3 => a 17 => b)»
routine join§
sub join(, *)method join(List: = "")
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: )multi map(, +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: # 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(, ) ;say <a b x y>.map().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()
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;s# OUTPUT: «hi»
method flatmap§
method flatmap(List: --> Seq)
Convenience method, analogous to .map(&block)
.flat
.
method gist§
multi method gist(List: --> Str)
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 , *, :, :, :, : --> Seq)method grep(List: Mu , :, :, :, : --> Seq)
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 , '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() # 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 , :kv, 'hello', 1, 22/7, 42, 'world';# OUTPUT: «(0 hello 2 3.142857 4 world)»say grep , :p, 'hello', 1, 22/7, 42, 'world';# OUTPUT: «(0 => hello 2 => 3.142857 4 => world)»
routine first§
sub first(Mu , *, :, :, :, :)method first(List: Mu ?, :, :, :, :)
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:) is rawmulti method head(Any: Callable )multi method head(Any: )
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:)multi method tail(List: --> Seq)
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( ); # OUTPUT: «(c d e)»
routine categorize§
multi method categorize()multi method categorize(Whatever)multi method categorize(, :!, :)multi method categorize(, :)multi categorize(, +items, :!, * )multi categorize(, +items, * )
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 ) returns Listsay categorize , (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(, :!, :)multi method classify(, :)multi classify(, +items, :!, * )multi classify(, +items, * )
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 , (1, 7, 6, 3, 2);# OUTPUT: «{even => [6 2], odd => [1 7 3]}»say ('hello', 1, 22/7, 42, 'world').classify: ;# 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( , :as);# 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( , :as, :into( my ) );say ; # 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: --> Bool)
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: --> Str)
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: --> Int)
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: --> Int)
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: --> Capture)
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 = (7, 5, a => 2, b => 17);my = .Capture;say .keys; # OUTPUT: «(0 1 a b)»my-sub(|); # OUTPUT: «7, 5, 2, 17»sub my-sub(, , :, :)
A more advanced example demonstrating the returned Capture
being matched against a Signature
.
my = (7, 5, a => 2, b => 17);say so .Capture ~~ :($ where * == 7,$,:,:); # OUTPUT: «True»= (8, 5, a => 2, b => 17);say so .Capture ~~ :($ where * == 7,$,:,:); # OUTPUT: «False»
routine pick§
multi pick(, * --> Seq)multi method pick(List: --> Seq)multi method pick(List: --> Mu)multi method pick(List: Callable --> Seq)
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(, * --> Seq)multi method roll(List: --> Seq)multi method roll(List: --> 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 lettersay <a b c d e>.roll: 3; # 3 random letterssay roll 8, <a b c d e>; # 8 random lettersmy := (^10).roll(*);say [^15]; # 15 random digits
routine eager§
multi method eager(List: --> List)
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(* --> Seq)multi method reverse(List: --> Seq)
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(, Int = 1 --> Seq)multi method rotate(List: Int = 1 --> Seq)
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(* --> Seq)multi sort(, * --> Seq)multi method sort(List: --> Seq)multi method sort(List: --> Seq)
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: ; # 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 = (%( first-name => 'Kyle', last-name => 'Reese' ),%( first-name => 'Sarah', last-name => 'Connor' ),%( first-name => 'John', last-name => 'Connor' ),);.say for .sort: ;#`(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( );# 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( );# 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: )multi reduce (, +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 :<+>, (1, 2, 3); # OUTPUT: «6»say (1, 2, 3).reduce: :<+>; # OUTPUT: «6»say reduce , (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 :<->, (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 , '', |strings; # like strings.joinmy \numbers = 1, 2, 3, 4, 5;say reduce , 0, |numbers; # like numbers.maxsub count-and-sum-evens( (Int \count, Int \sum), Int \x )say reduce , (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 Int
s 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(:<**>).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(:<->).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 ;say [[]] (1, 2, 3, 4); # OUTPUT: «24»
Semantically, all the following do the same thing:
my \numbers = 1, 2, 3, 4, 5;say reduce , 0, |numbers;say reduce * + *, 0, |numbers;say reduce &[+], numbers; # operator does not need explicit identity valuesay [+] 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 ;say (2, 3, 4, 5).reduce: ; # 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
.
sub infix:<foo>(, ) is assoc<right>say [foo] 1, 2, 3, 4; # OUTPUT: «(1, (2, (3, 4)))»sub infix:<bar>(, ) is assoc<left>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 = [Z] (<+ - * />, 1..20)».roll(4);say ('x', |).reduce: -> , [, ]
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 \c where c.all ~~ Int, Rat \x --> Rat)my \c = 2, 3, 1; # 2x² + 3x + 1say evaluate c, 3.0; # OUTPUT: «28»say evaluate c, 10.0; # OUTPUT: «231»
routine produce§
multi produce(, *)multi method produce(List: )
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 = (1,2,3,4,5);say produce , ;say produce * + *, ;say produce &[+], ; # operator does not need explicit identitysay [\+] ; # 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: ; # OUTPUT: «(2 5 9)»
routine combinations§
multi combinations(, = 0..* --> Seq)multi method combinations(List: Int() --> Seq)multi method combinations(List: Iterable = 0..* --> Seq)
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() --> Seq)multi permutations(Iterable --> Seq)multi method permutations(List: --> Seq)
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(*, Bool() : --> Seq)
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 , \source, Bool() : --> Seq)
multi rotor(*, \source, Bool() : --> Seq)
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 --> Seq)multi method batch(Int : --> 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(+, : --> Seq)
Computes the cross-product of two or more lists or Iterable
s. 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(:<*>)).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(+, : --> Seq)
Builds a 'list of lists', returned as a sequence, from multiple input lists or other Iterable
s.
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> -> [,,]# 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(:<*>);# 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 Iterable
s. 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, : --> 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( )method sum(List:)
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 = ^1_000_000;say .sum(:wrap); # OUTPUT: «499999500000»
method fmt§
method fmt( = '%s', = ' ' --> Str)
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 = 8..11;say .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 Match
es, 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 Pair
s:
my = (:42a, :33b);say ; # OUTPUT: «[a => 42 b => 33]»say .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 , List )
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»