list - 我怎样才能完全展平一个列表(列表(列表)......)

标签 list raku flatten

我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。

这与 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(*sublist)看起来很有趣,但答案要么是递归的,要么是硬编码的两个级别。函数式语言在源代码中是递归的,但我预料到了。

    最佳答案

    不幸的是,即使子列表包装在项目容器中,也没有直接的内置功能可以完全扁平化数据结构。

    一些可能的解决方案:

    收集/拍摄

    您已经想出了这样的解决方案,但是 deepmap可以处理所有的树迭代逻辑以简化它。它的回调对数据结构的每个叶节点调用一次,因此使用 take因为回调意味着 gather将收集叶子值的平面列表:

    sub reallyflat (+@list) { gather @list.deepmap: *.take }
    

    自定义递归函数

    您可以使用这样的子程序递归地 slip列出他们的 parent :

    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 )将其每个元素包装在一个新的项目容器中,无论它之前是否有一个。
  • 如何避免:如果您不需要 Array 提供的可变性,请使用 Lists of Lists 而不是 Arrays of Arrays。与 := 绑定(bind)可以用来代替赋值来存储 List@变量而不将其转换为 Array :my @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)
  • 关于list - 我怎样才能完全展平一个列表(列表(列表)......),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67515479/

    相关文章:

    string - 在 Haskell 中查找文本表中一列中最长的单词

    matlab - 将 3d 坐标存储在点列表中 Matlab

    raku - Perl6:函数/子例程的变元数目

    vector - 如何在 Clojure 中展平嵌套向量?

    python - 在 Python 中扁平化/反规范化 Dict/Json

    java - 接受未定义数量的数组的方法

    mysql - 我应该如何在 mysql 中插入/更新/删除大型列表?

    perl - 在 Perl 6 中调用类中的私有(private)方法

    benchmarking - 使用素数的Perl6 vs Perl5基准测试

    r - 展平数据框