List in Raku
— 焉知非鱼List in Raku
my class List is Iterable does Positional { .. }
List 以序列化的方式存储 items并且潜在是惰性的。
默认列表和数组的索引从 0 开始。
你可以给列表中的元素赋值如果它们是容器的话。使用数组以使列表中的每个元素存储在容器中。
Items、Flattening 和 Sigils #
在 Raku 中, 把 List 赋值给一个标量变量不会丢失信息。不同之处在于迭代通常会把标量中的列表当作单个元素。
my @a = 1, 2, 3;
for @a { } # 三次迭代
my $s = @a;
for $s { } # 一次迭代
for @a.item { } # 一次迭代
for $s.list { } # 三次迭代
Lists 通常会插值(展开)除非它们通过一个 item(scalar)容器访问:
my @a = 1, 2, 3;
my @flat = @a, @a; # two elements
my @nested = @a.item, @a.item; # two elements
.item
通常能被写为 $( ... )
, 而在数组变量上甚至写为 $@a
。
Methods #
elems #
multi sub elems($list) returns Int:D
multi method elems(List:D:) returns Int:D
返回列表中元素的个数。
end #
multi sub end($list) returns Int:D
multi method end(List:D:) returns Int:D
返回列表中最后一个元素的索引
keys #
multi sub keys($list) returns List:D
multi method keys(List:D:) returns List:D
返回一个索引列表( 例如 0..(@list.elems-1)
)
values #
multi sub values($list) returns List:D
multi method values(List:D:) returns List:D
返回列表的一份拷贝。
kv #
multi sub kv($list) returns List:D
multi method kv(List:D:) returns List:D
返回索引和值的交替的列表。例如:
<a b c>.kv
返回:
0, 'a', 1, 'b', 2, 'c'
pairs #
multi sub pairs($list) returns List:D
multi method pairs(List:D:) returns List:D
返回一个 pairs 的列表, 使用索引作为键, 列表值作为键值。
<a b c>.pairs # 0 => 'a', 1 => 'b', 2 => 'c'
join #
multi sub join($separator, *@list) returns Str:D
multi method join(List:D: $separator) returns Str:D
把列表中元素当作字符串, 在元素之间插入 $separator
并把所有东西连接成单个字符串。
例如:
join ', ', <a b c>; # 'a, b, c'
map #
multi sub map(&code, *@elems) returns List:D
multi method map(List:D: &code) returns List:D
对每个元素调用 &code
并且把值收集到另外一个列表中并返回它。这个过程是惰性的。&code
只在返回值被访问的时候调用。
例子:
('hello', 1, 22/7, 42, 'world').map: { .WHAT.raku }; # Str Int Rat Int Str
map *.Str.chars, 'hello', 1, 22/7, 42, 'world'; # 5 1 8 2 5
grep #
multi sub grep(Mu $matcher, *@elems) returns List:D
multi method grep(List:D: Mu $matcher) returns List:D
返回一个使用 $matcher
智能匹配的惰性列表。元素是以出现在原列表中的顺序返回的。
例子:
('hello', 1, 22/7, 42, 'world').grep: Int; # 1 42
grep { .Str.chars > 3 }, 'hello', 1, 22/7, 42, 'world'; # hello 3.142857 world
first #
multi sub first(Mu $matcher, *@elems)
multi method first(List:D: Mu $matcher)
返回列表中第一个匹配 $matcher
的元素, 当没有匹配值时, 失败。
例子:
say (1, 22/7, 42).first: * > 5; # 42
say $f = ('hello', 1, 22/7, 42, 'world').first: Complex;
('hello', 1, 22/7, 42, 'world',1+2i).first: Complex; # 1+2i
say $f.raku;
# Failure.new(exception => X::AdHoc.new(payload => "No values matched"))
classify #
multi sub classify(&mapper, *@values) returns Hash:D
multi method classify(List:D: &mapper) returns Hash:D
根据映射器把一列值转换成代表那些值的类别的散列; 散列的每个键代表着将要归入列表的一个或多个值的类别。比如字符个数, 元素多少, 键值就是根据 mapper 得到的这个类别下的元素, 它来自于原始列表:
例子:
say classify { $_ %% 2 ?? 'even' !! 'odd' }, (1, 7, 6, 3, 2);
# ("odd" => [1, 7, 3], "even" => [6, 2]).hash;
say ('hello', 1, 22/7, 42, 'world').classify: { .Str.chars };
# ("5" => ["hello", "world"], "1" => [1], "8" => [22/7], "2" => [42]).hash
Bool #
multi method Bool(List:D:) returns Bool:D
如果列表至少含有一个元素则返回 True, 如果列表为空则返回 False。
Str #
multi method Str(List:D:) returns Str:D
字符串化列表中的元素并使用空格把这些元素连接起来。( 和 .join(' ')
一样)。
Int #
multi method Int(List:D:) return Int:D
返回列表中元素的数量(和 .elems
一样)
pick #
multi sub pick($count, *@list) returns List:D
multi method pick(List:D: $count = 1)
从调用者身上随机返回 $count
个不重复的元素。 如果 *
作为 $count
传递进来或 $count
大于或等于列表的大小, 那么就以随机序列的方式返回列表中的所有元素。
例子:
say <a b c d e>.pick; # b
say <a b c d e>.pick: 3; # c a e
say <a b c d e>.pick: *; # e d a b c
roll #
multi sub roll($count, *@list) returns List:D
multi method roll(List:D: $count = 1)
返回一个 $count
个元素的惰性列表, 每个元素都从列表中随机选择。每个随机选择都是独立的.
如果给 $count
传递了 *
号, 则返回一个惰性的, 从原列表中随机选取元素的无限列表。
say <a b c d e>.roll; # b
say <a b c d e>.roll: 3; # c c e
say roll 8, <a b c d e>; # b a e d a e b c
my $random_digits := (^10).roll(*);1;
say $random_digits[^15]; # 3 8 7 6 0 1 3 2 0 8 8 5 8 0 5
eager #
multi method eager(List:D:) returns List:D
急切地计算列表中的所有元素, 并返回调用者。如果列表标示它是 “konw inifinite” 的, 急切求值可以停止在探测到的无限的点上。
reverse #
multi sub reverse(*@list ) returns List:D
multi method reverse(List:D:) returns List:D
以相反的顺序返回一个含有相同元素的列表。
注意 reverse
总是指反转列表中的元素, 如果你想反转字符串中的字符, 那么使用 flip。
say <hello world!>.reverse # world! hello
say reverse ^10 # 9 8 7 6 5 4 3 2 1 0
rotate #
multi sub rotate(@list, Int:D $n = 1) returns List:D
multi method rotate(List:D: Int:D $n = 1) returns List:D
以 $n
个元素旋转列表, 这把原列表分成两部分, 旋转中心就是在这两部分之间:
<a b c d e>.rotate(2); # <c d e a b>
<a b c d e>.rotate(-1); # <e a b c d>
sort #
multi sub sort(*@elems) returns List:D
multi sub sort(&by, *@elems) returns List:D
multi method sort(List:D:) returns List:D
multi method sort(List:D:, &by) returns List:D
列表排序, 最小的元素首先。默认使用 infix:<cmp>
排序列表中的元素。
如果提供了 &by
, 那么它接收两个参数, 它由列表元素对儿调用, 并且应该返回 Order::Increase
, Order::Same
或 Order::Decrease
。
如果 &by
只接受一个参数, 那么列表元素是通过 by($a) cmp by($b)
来排序的。&by
的返回值被缓存起来, 以使每个列表元素只调用一次 &by
。
say (3, -4, 7, -1, 2, 0).sort; # -4 -1 0 2 3 7
say (3, -4, 7, -1, 2, 0).sort: *.abs; # 0 -1 2 3 -4 7
say (3, -4, 7, -1, 2, 0).sort: { $^b leg $^a }; # 7 3 2 0 -4 -1
reduce #
multi sub reduce(&with, *@elems)
multi method reduce(List:D: &with)
把 &with
应用到列表中的第一个和第二个值上, 然后把 &with
应用到那个计算的结果值和第三个值上, 以此类推。按照那种方式生成单个项。
注意 reduce
是一个隐式的循环。
say (1, 2, 3).reduce: * - *; # -4
splice #
multi sub splice(@list, $start, $elems?, *@replacement) returns List:D
multi method splice(List:D: $start, $elems?, *@replacement) returns List:D
从列表中删除从 $start
索引开始的 $elems
个元素, 返回删除的元素并用 @replacement
来代替它。如果省略了 $elems
, 所有从 $index
开始的元素都被删除。
my @foo = <a b c d e f g>;
say @foo.splice(2, 3, <M N O P>); # c d e
say @foo; # a b M N O P f g
pop #
multi sub pop(List:D )
multi method pop(List:D:)
从列表中移除并返回最后一项。如果列表为空则失败。
> my @foo = <a b>;
> @foo.pop; # b
> pop @foo # a
> pop @foo # Element popped from empty list
push #
multi sub push(List:D, *@values) returns List:D
multi method push(List:D: *@values) returns List:D
把 @values
添加到列表的末尾, 并返回修改后的列表。 如果列表是无限列表则失败。
my @foo = <a b c>;
@foo.push: 1, 3 ... 11;
say @foo; # a b c 1 3 5 7 9 11
shift #
multi sub shift(List:D )
multi method shift(List:D:)
从列表中移除并返回第一项元素。如果列表为空则失败。
my @foo = <a b>;
say @foo.shift; # a
say @foo.shift; # b
say @foo.shift; # Element shifted from empty list
unshift #
multi sub unshift(List:D, *@values) returns List:D
multi method unshift(List:D: *@values) returns List:D
添加 @values
到列表的开头, 并返回修改后的列表。如果列表是无限列表则失败。
my @foo = <a b c>;
@foo.unshift: 1, 3 ... 11;
say @foo; # 1 3 5 7 9 11 a b c
combinations #
multi method combinations (List:D: Int:D $of) returns List:D
multi method combinations (List:D: Range:D $of = 0..*) returns List:D
multi sub combinations ($n, $k) returns List:D
Int 变体返回调用者列表所有的 $of-combinations
组合。例如:
say .join('|') for <a b c>.combinations(2);
打印
a|b
a|c
b|c
因为 ‘a’, ‘b’, ‘c’ 的所有 2-combinations 是 [‘a’, ‘b’], [‘a’, ‘c’], [‘b’, ‘c’].
Range 变体把所有单独的组合组合到单个列表中, 所以:
say .join('|') for <a b c>.combinations(2..3);
打印:
a|b
a|c
b|c
a|b|c
因为那是一个所有 2-和3-combinations 组合的列表。
子例程 combinations($n, $k)
等价于 (^$n).combinations($k)
, 所以:
.say for combinations(4, 2)
打印:
0 1
0 2
0 3
1 2
1 3
2 3
permutations #
multi method permutations(List:D:) returns List:D
multi sub permutations($n) returns List:D
返回列表所有可能的组合作为数组的列表。所以:
say .join('|') for <a b c>.permutations
打印:
a|b|c
a|c|b
b|a|c
b|c|a
c|a|b
c|b|a
permutations
把所有列表元素当作可区别的, 所以 (1, 1, 2).permutations
仍旧返回 6 个元素的列表, 即使只有 3 个不同的排列。
permutations($n)
等价于 (^$n).permutations
, 所以:
.say for permutations 3;
打印:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1