我怎样才能完全扁平化列表(列表(列表)...)
How can I completely flatten a list (of lists (of lists) ... )
我想知道如何完全扁平化列表和包含它们的东西。除其他事项外,我想出了这个解决方案,可以将具有多个元素的东西放回原位,或者在将其放入一个元素后将其放回原处。
这与 有点不同,后者并不完全平坦,因为任务是重组。
但是,也许有更好的方法。
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(*sublist)
看起来很有趣,但答案要么是递归的,要么仅限于硬编码的两个级别。函数式语言在源代码中是递归的,但我预料到了。
我不知道 built-in 这样做的方法,虽然很可能有(如果没有,可能应该有)。
我能在短时间内想到的最好的是:
gather @ab.deepmap(*.take)
我不确定 gather/take 如何与超级运算符的潜在并行计算交互,因此使用以下替代方法可能不安全,特别是如果您关心元素顺序:
gather @ab>>.take
如果需要数组,可以将代码放在方括号中,或者通过.list
将其具体化为列表。
最后,这是第一个重写为 retro-style 子例程的解决方案:
sub deepflat { gather deepmap &take, @_ }
不幸的是,没有直接的 built-in 可以完全扁平化数据结构,即使 sub-lists 被包裹在项目容器中也是如此。
一些可能的解决方案:
Gather/take
您已经提出了这样的解决方案,但是 deepmap
可以处理所有的树迭代逻辑来简化它。它的回调对数据结构的每个叶节点调用一次,因此使用 take
作为回调意味着 gather
将收集叶值的平面列表:
sub reallyflat (+@list) { gather @list.deepmap: *.take }
自定义递归函数
您可以使用这样的子例程递归 slip
列表到它们的父级:
multi reallyflat (@list) { @list.map: { slip reallyflat $_ } }
multi reallyflat (\leaf) { leaf }
另一种方法是递归地将 <>
应用到 sub-lists 以释放它们包装在其中的任何物品容器,然后在结果上调用 flat
:
sub reallyflat (+@list) {
flat do for @list {
when Iterable { reallyflat $_<> }
default { $_ }
}
}
Multi-dimensional数组索引
postcircumfix [ ]
运算符可以与 multi-dimensional 下标一起使用以获得达到一定深度的叶节点的平面列表,但不幸的是 "infinite depth" 版本尚未实现:
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.
不过,如果您知道数据结构的最大深度,这是一个可行的解决方案。
避免容器化
built-in flat
函数可以很好地展平深度嵌套的列表列表。问题只是它没有进入物品容器 (Scalar
s)。嵌套列表中意外项目容器的常见来源是:
一个 Array
(但不是 List
)将其每个元素包装在一个新的项目容器中,无论它之前是否有一个。
- 如何避免: 如果您不需要数组提供的可变性,请使用列表的列表而不是数组的数组。可以使用
:=
绑定而不是赋值,将 List
存储在 @
变量中而不将其转换为 Array
:
my @a := 'a', ('b', 'c' );
my @b := ('d',), 'e', 'f', @a;
say flat @b; # (d e f a b c)
$
变量是物品容器。
- 如何避免: 将列表存储在
$
变量中,然后将其作为元素插入到另一个列表中时,使用 <>
去容器化它。将父列表的容器传递给 flat
时,也可以使用 |
绕过它:
my $a = (3, 4, 5);
my $b = (1, 2, $a<>, 6);
say flat |$b; # (1 2 3 4 5 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(*sublist)
看起来很有趣,但答案要么是递归的,要么仅限于硬编码的两个级别。函数式语言在源代码中是递归的,但我预料到了。
我不知道 built-in 这样做的方法,虽然很可能有(如果没有,可能应该有)。
我能在短时间内想到的最好的是:
gather @ab.deepmap(*.take)
我不确定 gather/take 如何与超级运算符的潜在并行计算交互,因此使用以下替代方法可能不安全,特别是如果您关心元素顺序:
gather @ab>>.take
如果需要数组,可以将代码放在方括号中,或者通过.list
将其具体化为列表。
最后,这是第一个重写为 retro-style 子例程的解决方案:
sub deepflat { gather deepmap &take, @_ }
不幸的是,没有直接的 built-in 可以完全扁平化数据结构,即使 sub-lists 被包裹在项目容器中也是如此。
一些可能的解决方案:
Gather/take
您已经提出了这样的解决方案,但是 deepmap
可以处理所有的树迭代逻辑来简化它。它的回调对数据结构的每个叶节点调用一次,因此使用 take
作为回调意味着 gather
将收集叶值的平面列表:
sub reallyflat (+@list) { gather @list.deepmap: *.take }
自定义递归函数
您可以使用这样的子例程递归 slip
列表到它们的父级:
multi reallyflat (@list) { @list.map: { slip reallyflat $_ } }
multi reallyflat (\leaf) { leaf }
另一种方法是递归地将 <>
应用到 sub-lists 以释放它们包装在其中的任何物品容器,然后在结果上调用 flat
:
sub reallyflat (+@list) {
flat do for @list {
when Iterable { reallyflat $_<> }
default { $_ }
}
}
Multi-dimensional数组索引
postcircumfix [ ]
运算符可以与 multi-dimensional 下标一起使用以获得达到一定深度的叶节点的平面列表,但不幸的是 "infinite depth" 版本尚未实现:
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.
不过,如果您知道数据结构的最大深度,这是一个可行的解决方案。
避免容器化
built-in flat
函数可以很好地展平深度嵌套的列表列表。问题只是它没有进入物品容器 (Scalar
s)。嵌套列表中意外项目容器的常见来源是:
一个
Array
(但不是List
)将其每个元素包装在一个新的项目容器中,无论它之前是否有一个。- 如何避免: 如果您不需要数组提供的可变性,请使用列表的列表而不是数组的数组。可以使用
:=
绑定而不是赋值,将List
存储在@
变量中而不将其转换为Array
:my @a := 'a', ('b', 'c' ); my @b := ('d',), 'e', 'f', @a;
say flat @b; # (d e f a b c)
- 如何避免: 如果您不需要数组提供的可变性,请使用列表的列表而不是数组的数组。可以使用
$
变量是物品容器。- 如何避免: 将列表存储在
$
变量中,然后将其作为元素插入到另一个列表中时,使用<>
去容器化它。将父列表的容器传递给flat
时,也可以使用|
绕过它:my $a = (3, 4, 5); my $b = (1, 2, $a<>, 6);
say flat |$b; # (1 2 3 4 5 6)
- 如何避免: 将列表存储在