问题描述
我想知道如何才能完全弄平列表以及包含列表的内容.除其他事项外,我想出了一种解决方案,可以将具有多个元素的东西放回去并放回去,或者将具有一个元素的东西放回去后再放回去.
I was wondering about how I could completely flatten lists and things that contain them. Among other things, I came up with this solution that slips things that have more than one element and puts them back, or takes things with one element after slipping it.
这与在perl 6中如何拉平"列表列表有些不同?并非完全平坦,因为任务是进行重组.
This is a bit different than How do I "flatten" a list of lists in perl 6?, which doesn't completely flat because the task is to restructure.
但是,也许有更好的方法.
But, maybe there's a better way.
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答案:
Curiously, I also read some python answers:
- 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(*sublist)
看起来很有趣,但是答案要么是递归的,要么是硬编码的两个级别.功能语言在源代码中是递归的,但我希望如此.
itertools.chain(*sublist)
look interesting, but the answers were either recursive or limited to two levels from hard-coding. The functional languages were recursive in the source code, but I expected that.
推荐答案
不幸的是,即使子列表包装在项目容器中,也没有直接内置的方法可以完全拉平数据结构.
Unfortunately there's no direct built-in that completely flattens a data structure even when sub-lists are wrapped in item containers.
一些可能的解决方案:
您已经想出了这样的解决方案,但是deepmap
可以处理所有的树迭代逻辑来简化它.对于数据结构的每个叶子节点,都会对其回调调用一次,因此,使用take
作为回调意味着gather
将收集叶子值的平面列表:
You've already come up with a solution like this, but deepmap
can take care of all the tree iteration logic to simplify it. Its callback is called once for every leaf node of the data structure, so using take
as the callback means that gather
will collect a flat list of the leaf values:
sub reallyflat (+@list) { gather @list.deepmap: *.take }
自定义递归函数
您可以使用这样的子例程将slip
列表递归地添加到其父级:
Custom recursive function
You could use a subroutine like this to recursively slip
lists into their parent:
multi reallyflat (@list) { @list.map: { slip reallyflat $_ } }
multi reallyflat (\leaf) { leaf }
另一种方法是将<>
递归应用于子列表,以释放它们所包裹的所有项目容器,然后在结果上调用flat
:
Another approach would be to recursively apply <>
to sub-lists to free them of any item containers they're wrapped in, and then call flat
on the result:
sub reallyflat (+@list) {
flat do for @list {
when Iterable { reallyflat $_<> }
default { $_ }
}
}
多维数组索引
postcircumfix [ ]
运算符可以与多维下标一起使用,以获取直至一定深度的叶节点的平面列表,尽管遗憾的是尚未实现无限深度"版本:
Multi-dimensional array indexing
The postcircumfix [ ]
operator can be used with a multi-dimensional subscript to get a flat list of leaf nodes up to a certain depth, though unfortunately the "infinite depth" version is not yet implemented:
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.
不过,如果您知道数据结构的最大深度,那么这是一个可行的解决方案.
Still, if you know the maximum depth of your data structure this is a viable solution.
内置的flat
函数可以使深度嵌套的列表列表变平.问题在于它不属于项目容器(Scalar
s).嵌套列表中意外容器的常见来源是:
The built-in flat
function can flatten a deeply nested lists of lists just fine. The problem is just that it doesn't descend into item containers (Scalar
s). Common sources of unintentional item containers in nested lists are:
-
Array
(但不是List
)将每个元素包装在新鲜的项目容器中,无论之前是否有过.
An
Array
(but notList
) wraps each of its elements in a fresh item container, no matter if it had one before.
- 如何避免:如果不需要Array提供的可变性,请使用列表列表而不是数组数组.可以使用
:=
绑定而不是赋值,将List
存储在@
变量中,而无需将其转换为Array
:
- How to avoid: Use Lists of Lists instead of Arrays of Arrays, if you don't need the mutability that Array provides. Binding with
:=
can be used instead of assignment, to store aList
in a@
variable without turning it into anArray
:
my @a := 'a', ('b', 'c' );
my @b := ('d',), 'e', 'f', @a;
say flat @b; # (d e f a b c)
$
变量是项目容器.
- 如何避免:将列表存储在
$
变量中,然后将其作为元素插入到另一个列表中时,请使用<>
对其进行去容器化.将父列表的容器传递给flat
时,也可以使用|
绕过它:
- How to avoid: When storing a list in a
$
variable and then inserting it as an element into another list, use<>
to decontainerize it. The parent list's container can also be bypassed using|
when passing it toflat
:
my $a = (3, 4, 5);
my $b = (1, 2, $a<>, 6);
say flat |$b; # (1 2 3 4 5 6)
这篇关于我如何才能完全展平(列表(的列表)...)的Perl 6列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!