我怎样才能完全展平一个列表(列表(列表)......)
Posted
技术标签:
【中文标题】我怎样才能完全展平一个列表(列表(列表)......)【英文标题】:How can I completely flatten a list (of lists (of lists) ... ) 【发布时间】:2017-05-29 14:56:55 【问题描述】:我想知道如何完全扁平化列表和包含它们的事物。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。
这与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 listsitertools.chain(*sublist)
看起来很有趣,但答案要么是递归的,要么是硬编码的两个级别。函数式语言在源代码中是递归的,但我预料到了。
【问题讨论】:
【参考方案1】:不幸的是,即使子列表包装在项目容器中,也没有直接的内置函数可以完全扁平化数据结构。
一些可能的解决方案:
收集/采取
您已经想出了这样的解决方案,但是deepmap
可以处理所有的树迭代逻辑以简化它。它的回调为数据结构的每个叶节点调用一次,因此使用take
作为回调意味着gather
将收集叶值的平面列表:
sub reallyflat (+@list) gather @list.deepmap: *.take
自定义递归函数
您可以使用这样的子例程以递归方式将slip
列表添加到它们的父级中:
multi reallyflat (@list) @list.map: slip reallyflat $_
multi reallyflat (\leaf) leaf
另一种方法是递归地将<>
应用到子列表以释放它们所包裹的任何项目容器,然后在结果上调用flat
:
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.
不过,如果您知道数据结构的最大深度,这是一个可行的解决方案。
避免容器化
内置的flat
函数可以很好地展平深度嵌套的列表列表。问题只是它没有下降到项目容器中(Scalar
s)。嵌套列表中意外项容器的常见来源是:
Array
(但不是List
)将其每个元素包装在一个新的项目容器中,无论它之前是否有一个。
:=
绑定来代替赋值,将List
存储在@
变量中,而不会将其转换为Array
:我的@a := 'a', ('b', 'c' ); 我的@b := ('d',), 'e', 'f', @a; 说平@b; # (d e f a b c)
$
变量是物品容器。
$
变量中,然后将其作为元素插入到另一个列表中时,使用<>
将其解容器。在将父列表的容器传递给flat
时,也可以使用|
绕过它:我的 $a = (3, 4, 5); 我的 $b = (1, 2, $a, 6); 说平 |$b; # (1 2 3 4 5 6)
【讨论】:
是否有机会将这样的deepflat
函数(或运算符,我指定||
它还没有被使用)添加到 6.d?
我有点喜欢使用没有大括号/括号的现有内置插件:say gather @ab.deepmap: *.take;
.
@raiph:看起来确实更好。已更新。
@mscha speculations 建议拉里的意图是保留前缀: 以“在分号级别将列表插入分号列表”,并且 deepflat 的预期解决方案是 @987654349 @下标。
深度图 FTW。至于“避免容器”,有时你不得不拿别人给你的东西。最好的解决方案可以解决所有问题。【参考方案2】:
我不知道这样做的内置方法,尽管很可能有(如果没有,可能应该有)。
我能在短时间内想出的最好办法是:
gather @ab.deepmap(*.take)
我不确定收集/获取如何与超级运算符的潜在并行评估交互,因此使用以下替代方法可能不安全,特别是如果您关心元素顺序:
gather @ab>>.take
如果需要数组,可以将代码放入方括号中,或者通过.list
将其具体化为列表。
最后,这是第一个被改写为复古风格子程序的解决方案:
sub deepflat gather deepmap &take, @_
【讨论】:
嘿,我没有看到你已经想出了相同的deepmap
解决方案,而我正在写我的答案......是的,一旦 »
学会像设计文档一样并行化自己预期,您的第二个解决方案很可能不会以正确的顺序返回元素。
[x] 移除了迷信的大括号(并添加了 deepflat
实现)以上是关于我怎样才能完全展平一个列表(列表(列表)......)的主要内容,如果未能解决你的问题,请参考以下文章