sirve - ¿Cómo puedo aplanar completamente una lista de Perl 6(de listas(de listas)...)
perl wikipedia español (2)
Desafortunadamente, no hay una incorporación directa que aplane completamente la estructura de datos, incluso cuando las sub-listas están envueltas en contenedores de elementos.
Algunas posibles soluciones:
Recoger / tomar
Ya ha encontrado una solución como esta, pero deepmap
puede encargarse de toda la lógica de iteración de árbol para simplificarla. Se llama a su devolución de llamada una vez para cada nodo de hoja de la estructura de datos, por lo que usar take
como medio de devolución de llamada que gather
recopilará una lista plana de los valores de hoja:
sub reallyflat (+@list) { gather @list.deepmap: *.take }
Función recursiva personalizada
Podría usar una subrutina como esta para slip
recursivamente las listas a sus padres:
multi reallyflat (@list) { @list.map: { slip reallyflat $_ } }
multi reallyflat (/leaf) { leaf }
Otro enfoque sería aplicar de forma recursiva <>
a las sub-listas para liberarlos de los contenedores de elementos en los que están envueltos, y luego llamar flat
al resultado:
sub reallyflat (+@list) {
flat do for @list {
when Iterable { reallyflat $_<> }
default { $_ }
}
}
Indexación multidimensional de matrices
El operador postcircumfix [ ]
se puede usar con un subíndice multidimensional para obtener una lista plana de nodos de hoja hasta una cierta profundidad, aunque desafortunadamente la versión de "profundidad infinita" aún no está implementada:
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.
Sin embargo, si conoce la profundidad máxima de su estructura de datos, esta es una solución viable.
Evitar la contenedorización
La función flat
incorporada puede aplanar una lista de listas profundamente anidadas bien. El problema es que no desciende a los contenedores de elementos ( Scalar
s). Las fuentes comunes de contenedores de elementos no intencionales en listas anidadas son:
Una
Array
(pero no laList
) envuelve cada uno de sus elementos en un contenedor de elementos nuevos, sin importar si tenía uno antes.- Cómo evitarlo: use Listas de listas en lugar de Arrays of Arrays, si no necesita la mutabilidad que proporciona Array. La vinculación con
:=
se puede usar en lugar de la asignación, para almacenar unaList
en una variable@
sin convertirla en unArray
:my @a := ''a'', (''b'', ''c'' ); my @b := (''d'',), ''e'', ''f'', @a;
say flat @b; # (d e f a b c)
- Cómo evitarlo: use Listas de listas en lugar de Arrays of Arrays, si no necesita la mutabilidad que proporciona Array. La vinculación con
$
variables son contenedores de elementos.- Cómo evitarlo: Cuando almacene una lista en una variable
$
y luego la inserte como un elemento en otra lista, use<>
para descongelarla. El contenedor de la lista de padres también se puede omitir usando|
Al pasarlo alflat
:my $a = (3, 4, 5); my $b = (1, 2, $a<>, 6);
say flat |$b; # (1 2 3 4 5 6)
- Cómo evitarlo: Cuando almacene una lista en una variable
Me preguntaba cómo podría aplanar completamente las listas y las cosas que las contienen. Entre otras cosas, se me ocurrió esta solución que desliza las cosas que tienen más de un elemento y las vuelve a colocar, o las toma con un elemento después de deslizarla.
Esto es un poco diferente a ¿Cómo "aplano" una lista de listas en Perl 6? , que no es completamente plana porque la tarea es reestructurar.
Pero, tal vez hay una mejor manera.
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;
Esto da:
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]
Curiosamente, también leí algunas respuestas de python:
- Hacer una lista plana de la lista de listas en Python
- Cómo aplanar una lista de listas un paso
- Aplanar la lista de listas de listas a una lista de listas
itertools.chain(*sublist)
parece interesante, pero las respuestas fueron recursivas o se limitaron a dos niveles de codificación rígida. Los lenguajes funcionales eran recursivos en el código fuente, pero esperaba eso.
No conozco una forma integrada de hacerlo, aunque podría haberlo (y si no, probablemente debería haberlo).
Lo mejor que pude encontrar en poco tiempo es esto:
gather @ab.deepmap(*.take)
No estoy seguro de cómo interactuar recopilación / toma con la evaluación potencialmente paralela de los operadores de hiperactivos, por lo que la siguiente alternativa podría no ser segura de usar, en particular si le importa el orden de los elementos:
gather @ab>>.take
Puede poner el código entre corchetes si necesita una matriz o volver a clasificarlo en una lista a través de .list
.
Por último, esta es la primera solución rewitten como una subrutina de estilo retro:
sub deepflat { gather deepmap &take, @_ }