这与How do I “flatten” a list of lists in perl 6?有点不同,因为任务是重组,这并不完全平坦.
但是,也许有更好的方法.
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;
这给出:
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]
奇怪的是,我也读了一些python的答案:
> Making a flat list out of list of lists in Python
> How flatten a list of lists one step
> flatten list of lists of lists to a list of lists
itertools.chain(*子列表)看起来很有趣,但答案是递归的,或者限于硬编码的两个级别.功能语言在源代码中递归,但我预计.
解决方法
一些可能的解决方案:
收集/取
您已经提出了这样的解决方案,但是deepmap可以处理所有的树式迭代逻辑来简化它.对于数据结构的每个叶节点,它的回调被调用一次,因此使用take作为回调方法,即收集将收集叶值的平面列表:
sub reallyflat (+@list) { gather @list.deepmap: *.take }
您可以使用这样的子程序将列表递归递送到父级中:
multi reallyflat (@list) { @list.map: { slip reallyflat $_ } } multi reallyflat (\leaf) { leaf }
另一种方法是递归地应用<到子列表中释放他们包装的任何物品容器,然后调用结果:
sub reallyflat (+@list) { flat do for @list { when Iterable { reallyflat $_<> } default { $_ } } }
多维数组索引
postcircumfix []运算符可以与多维下标一起使用,以获得一定长度的叶节点的平面列表,尽管不幸的是“无限深度”版本尚未实现:
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.
但是,如果您知道数据结构的最大深度,这是一个可行的解决方案.
避免集装箱化
内置的平面功能可以平滑一个深入嵌套的列表列表.问题在于它不会下降到项目容器(Scalars)中.嵌套列表中无意的项目容器的常见来源有:
>一个数组(但不是列表)将其每个元素包装在一个新的项目容器中,无论以前是否有一个元素.
>如何避免:使用列表而不是数组数组,如果您不需要Array提供的可变性.绑定:=可以使用而不是赋值,将列表存储在@变量中,而不将其转换为数组:
my @a := 'a','c' ); my @b := ('d',@a;
say flat @b; # (d e f a b c)
> $变量是项容器.
>如何避免:将列表存储在$变量中,然后将其作为元素插入到另一个列表中时,使用<>去掉它.也可以使用|绕过父列表的容器当把它传递给平:
my $a = (3,4,5); my $b = (1,2,$a<>,6); say flat |$b; # (1 2 3 4 5 6)