如何完全展平Perl 6列表(列表列表)...)

时间:2017-01-14 08:27:43

标签: list perl6 flatten raku

我想知道如何完全展平列表和包含它们的内容。除此之外,我想出了这个解决方案,它可以滑动具有多个元素的东西并将它们放回去,或者在滑动之后用一个元素处理它。

这与How do I “flatten” a list of lists in perl 6?略有不同,Making a flat list out of list of lists in Python不完全平坦,因为任务是重组。

但是,也许有更好的方法。

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答案:

itertools.chain(*sublist)看起来很有趣,但答案要么是递归的,要么限于硬编码的两个级别。功能语言在源代码中是递归的,但我期望这样。

2 个答案:

答案 0 :(得分:8)

不幸的是,即使子列表包含在项容器中,也没有直接内置的数据结构完全展平。

一些可能的解决方案:

收集/取

您已经提出了这样的解决方案,但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 [ ]运算符可以与多维下标一起使用,以获得直到某个深度的叶节点的平面列表,但不幸的是,&#34;无限深度&#34;版本尚未实施:

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)将每个元素包装在一个新的项目容器中,无论它之前是否有过。

    • 如何避免:如果您不需要Array提供的可变性,请使用Lists列表而不是Arrays of Arrays。可以使用:=绑定代替分配,将List存储在@变量中,而不将其转换为Array
      my @a  := 'a', ('b', 'c' );
      my @b  := ('d',), 'e', 'f', @a;
      say flat @b; # (d e f a b c)
  • $变量是项容器。

    • 如何避免:将列表存储在$变量中,然后将其作为元素插入到另一个列表中时,使用<>对其进行去包容。在将|传递给flat时,也可以使用outlineImage.onload = resourceLoaded; outlineImage.src = "images/watermelon-duck-outline.png"; 绕过父列表的容器:
      my $a = (3, 4, 5);
      my $b = (1, 2, $a<>, 6);
      say flat |$b; # (1 2 3 4 5 6)

答案 1 :(得分:6)

我没有意识到这样做的内置方式,尽管可能很好(如果没有,可能应该有)。

我能在短时间内提出的最佳结果是:

gather @ab.deepmap(*.take)

我不确定如何收集/采用可能并行化的超级运算符评估,因此以下替代方案可能不安全,特别是如果您关心元素顺序:

gather @ab>>.take

如果您需要数组或通过.list将其重新列入列表,您可以将代码放入方括号中。

最后,这是第一个作为复古风格子程序重新设置的解决方案:

sub deepflat { gather deepmap &take, @_ }