2017 StackOverFlow-sort,deepmap,flat

我想匹配任意一组单词,但是失败了,请问怎样才能正确地匹配到?

1
2
3
my @a=<a b c d e f>;
my $x="a1234567";
say $x ~~ m/ @a.any /;

Answer

1
2
3
my @a = <a b c d e f>;
my $x = "a1234567";
say $x ~~ /@a/

/@a//| @a/ 相同,它是最长的备选分支。对于备选分支,你可以使用 /|| @a/

1
2
3
4
5
sub foo($x) {
$x**2
}
my $alist = (1,2, &foo ... ^ * > 100);

我想得到 (1 4 9 16 25 .. ) 而程序得到的是 (1 2 4 16 256)

Answer:

1
2
my @a = (1..*).map(* ** 2); # using a Whatever-expression
my @a = (1..*).map(&foo); # using your `foo` function

或者使用 Haskell/Python 那样的列表解析式:

1
2
my @a = ($_ ** 2 for 1..*); # using an in-line expression
my @a = (foo $_ for 1..*); # using your `foo` function

另外还有一种方法:

1
2
3
4
5
my @alist = {(++$)²} ... * > 70; # stop immediately after past 70
say @alist; # [1 4 9 16 25 36 49 64 81]
my @alist = {(++$)²} ...^ * > 70; # stop immediately before past 70
say @alist; # [1 4 9 16 25 36 49 64]

个人不推荐使用 $ 匿名变量的这种写法, 对于 new comer 不太友好。

Is it possible to use junction to match any of the values in a junction? I want to match any of the values in an array. What is the proper way to do it?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> my @a=<a b c>
[a b c]
> any(@a)
any(a, b, c)
> my $x=any(@a)
any(a, b, c)
> my $y = "a 1"
a 1
> say $y ~~ m/ $x /
False
> say $y ~~ m/ "$x" /
False
> my $x = any(@a).Str
any("a", "b", "c")
> say $y ~~ m/ $x /
False
> say $y ~~ m/ || $x /
False
> say $y ~~ m/ || @a /
「a」

Answer

junctions 不该被插值到正则表达式中。它们应该被用在普通的 Perl 6 表达式中,特别是带有比较操作符的表达式(例如 eq):

1
2
3
my @a = <x y z>;
say "y" eq any(@a); # any(False, True, False)
say so "y" eq any(@a); # True

要在正则表达式中匹配一个数组的任意值,就在正则表达式中写上那个数组名好了(以@开头)。默认地,这被插值为 | 备选分支(“longest match”),但是你也可以把他指定为 || 备选分支(“first match”)。

1
2
3
my @a = <foo bar barkeep>;
say "barkeeper" ~~ / @a /; # 「barkeep」
say "barkeeper" ~~ / || @a /; # 「bar」

我需要排序数组的数组, .sort 方法能不能按照内层数组的不同索引来排序呢?

要排序的数组在一个更大的数组的外面:(birthday 是 ‘mmddyy’ 格式的:)

1
2
3
4
5
6
my @allRecords = [ [birthday1 firstName1 lastName1 [data1]
[birthday2 firstName2 lastName2 [data2]
...
[birthdayN firstNameN lastNameN [dataN] ];
@allRecords.sort by itself sorts by birthdays.

有什么好方法能按照 firstName 或 lastName 或 按照内层数组里面的数据来排序?

Answer

sort 方法接受一个可选的 sub 参数_routine_sort)。如果元数是 1, 那么它使用返回值作为比较操作数;如果元数为 2, 那么你可以在两个元素之间手动作比较,两个元素的比较会返回 Less, Same, More

拿你上面的例子来说,我们可以像这样按照 first name 进行排序:

1
@allRecords.sort(*.[1])

我们可以先按照 last name 再按照 first name 进行排序,然后按照 birthday 来做单独的比较,就像这样:

1
2
3
@allRecords.sort(-> $a,$b {
$a[2] cmp $b[2] || $a[1] cmp $b[1] || $a[0] cmp $b[0]
});

或者再次通过转换操作数:

1
@allRecords.sort(*.[2...0]);

变换 birthday 条目以至于我们能先按照 year 排序作为练习留给读者完成,但是其中一种方法是在合适的地方添加像这样的代码:

1
.comb(2).list.rotate(-1).join

你可以按照 lastname,firstname, birthday 这样的顺序排序:

1
@a.sort: *[2...0]

还有两个问题:

  • *.[1]*[1] 有什么区别?

两者没有任何区别,但是前者可读性更好!

  • range 操作符和 … 序列操作符有什么区别

range 不能倒数, ... 可以倒数。

在 Perl 6 中怎样找出列表中最大值的索引?

Answer

1
2
my @list = 1,2,9,6,9,5;
@list.maxpairs; # [2 => 9 4 => 9]

@list.maxpairs 用于获取索引和对应最大值的所有对儿。
@list.pairs.max(*.value).key 用于仅获取单个索引。

1
2
> @list.pairs.max(*.value).key
2

如何彻底地展平 Perl 6 的列表?这个问题不同于 How do I “flatten” a list of lists in perl 6?, 后者不是彻底的 flat。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
my @a = 'a', ('b', 'c' );
my @b = ('d',), 'e', 'f', @a;
my @c = 'x', $( 'y', 'z' ), 'w';
my @ab = @a, @b, @c;
say "ab: ", @ab;
my @f = @ab;
@f = gather {
while @f {
@f[0].elems == 1 ??
take @f.shift.Slip
!!
@f.unshift( @f.shift.Slip )
}
}
say "f: ", @f;

这打印出:

1
2
ab: [[a (b c)] [(d) e f [a (b c)]] [x (y z) w]]
f: [a b c d e f a b c x y z w]

但这不够简洁。一种可行的办法是使用:gather/take/deepmap:

1
say gather @ab.deepmap(*.take)

postcircumfix [] 操作符可用于多维下标来获取一组展平的叶子节点,直到特定的深度,尽管 “无限深度” 版本还没有实现:

1
2
3
4
say @ab[*;*]; # (a (b c) (d) e f [a (b c)] x (y z) w)
say @ab[*;*;*]; # (a b c d e f a (b c) x y z w)
say @ab[*;*;*;*]; # (a b c d e f a b c x y z w)
say @ab[**]; # HyperWhatever in array index not yet implemented. Sorry.
  • 避免容器化 (containerization)

内置的 flat 函数能很好地展平深度嵌套的列表。问题是它不能落进 item 容器(Scalar)中。嵌套列表中非故意的 item 容器的常见来源有:

  • 数组(但不是列表)将其每个元素包装在一个新的 item 容器中,无论它之前有没有。
    • 如何避免:如果不需要 Array 提供的可变性,请使用列表的列表而不是数组的数组。使用绑定 := 可以用来代替赋值,将列表存储在@变量中,而不将其转换为数组
1
2
3
4
my @a := 'a', ('b', 'c' );
my @b := ('d',), 'e', 'f', @a;
say flat @b; # (d e f a b c)
  • $variables 是 item 容器。
    • 如何避免:当将列表存储在 $ 变量中,然后将其作为元素插入到另一个列表中时,使用 <> 来对它进行 decontainerize(解容器化)。当把 $ 变量传递给 flat 时, 父列表的容器也可以使用 | 绕过:
1
2
3
4
my $a = (3, 4, 5);
my $b = (1, 2, $a<>, 6);
say flat |$b; # (1 2 3 4 5 6)

未完待续。。。

------ Young For Perl 6! ------