Desplegar una matriz


34

Este desafío fue inspirado por una pregunta en Mathematica.SE .

Digamos que tiene una lista / matriz anidada de alguna estructura arbitraria (las listas en cada nivel no necesariamente tienen la misma longitud). Para simplificar, asumiremos que los nodos son enteros no negativos o matrices vacías. Como ejemplo

[[[1, 3], 2], [1, 4], 12, [[0, [], 0], [5, [7]]]]

A veces es más conveniente aplanar esa lista para realizar alguna manipulación de los nodos, p. Ej.

--> [1, 3, 2, 1, 4, 12, 0, 0, 5, 7]
--> [1, 1, 0, 1, 0, 0, 0, 0, 1, 1]

Pero al final, realmente desea preservar la estructura original, por lo que desea volver a convertir esto en

--> [[[1, 1], 0], [1, 0], 0, [[0, [], 0], [1, [1]]]

Su tarea es realizar ese último paso.

Dada una lista anidada de enteros no negativos arbitrarios, que representa la estructura deseada del resultado, y una lista plana de enteros no negativos, que representan los valores deseados, reconfigura la lista plana en la forma de la lista estructurada. Puede suponer que ambas listas contienen el mismo número de enteros.

Como de costumbre, no tiene que lidiar con entradas no válidas (por ejemplo, la segunda lista no es plana, la entrada tiene una forma sintáctica incorrecta, no tiene enteros como nodos, etc.) Puede modificar las matrices de entrada en su código.

Puede escribir una función o programa, tomando datos a través de STDIN, argumento de línea de comando o argumento de función, y puede devolver el resultado o imprimirlo en STDOUT. Puede usar cualquier formato conveniente de lista o cadena para representar la entrada y la salida (siempre que el formato no sea ambiguo y la entrada no esté preprocesada). Además, el formato de ambas entradas debe ser coherente (por lo que no puede tomar una entrada como una cadena y la otra como una lista, por ejemplo). Puede tomar las listas de entrada en cualquier orden, pero especifique el método de entrada exacto en su respuesta.

Una restricción más: no debes usar expresiones regulares. Este es un desafío de manipulación de matriz, no un desafío de manipulación de cadenas.

Este es el código de golf, por lo que gana la respuesta más corta (en bytes).

Casos de prueba

Structure                             Values                 Result
[[[1,3],2],[1,4],12,[[0,0],[5,[7]]]]  [1,1,0,1,0,0,0,0,1,1]  [[[1,1],0],[1,0],0,[[0,0],[1,[1]]]]
[[[0,0],0],[0,0],0,[[0,0],[0,[0]]]]   [1,1,0,1,0,0,0,0,1,1]  [[[1,1],0],[1,0],0,[[0,0],[1,[1]]]]
[]                                    []                     []
[[]]                                  []                     [[]]
[0,1,2,3]                             [5,1,0,5]              [5,1,0,5]
[[[[[0]]]]]                           [123]                  [[[[[123]]]]]
[0,[1,[]],[[]],[2,3],[]]              [1,6,1,8]              [1,[6,[]],[[]],[1,8],[]]

¿Está permitido si los valores en la matriz Estructura cambian?
ProgramFOX

@ProgramFOX sí. "Puede modificar las matrices de entrada en su código".
Martin Ender

Irónicamente, una de las presentaciones aquí está en Mathematica.
Isiah Meadows

1
@impinball Eso es mío, que publiqué junto con la pregunta, para evitar que alguien más robe la respuesta de la pregunta vinculada (y de hecho, es simplemente una versión reducida de esa respuesta).
Martin Ender

@ MartinBüttner Oh. Agradable. En realidad, también es una de las respuestas más cortas.
Isiah Meadows

Respuestas:


9

CJam, 18 16 13 bytes

lA,sNerN%l~]z

Toma entrada a través de STDIN en el mismo formato que la respuesta anterior de CJam:

[0 [11 []] [[]] [2 3] []]
[1 6 1 8] 

y envía la cadena de resultado a STDOUT

[1 [6 []] [[]] [1 8] []]

Simplemente trato la primera línea como una cadena, convierto todos los caracteres de dígitos a nuevas líneas, se divide en una o más apariciones de nuevas líneas, pongo la segunda línea como una matriz en la pila, envuelvo en una matriz y unimos las dos matrices (filas). La impresión es automática y, como la primera fila se trató como una cadena, conserva sus corchetes.

Expansión de código

lA,sNerN%l~]z
l                     "Read the first line of input. This is the nested array";
 A,s                  "Get array [0,1,2...9] and  convert it to string '012..9'";
    Ner               "Replace all occurrences of 0,1,2,..9 with new line";
       N%             "Split on one or more occurrences of new line";
         l~           "Read the second line as an array";
           ]          "Wrap both the splitted string and the second line array";
                      "in an array";
            z         "Transpose the array, there by placing the numbers from second";
                      "input array in the split holes of first input string";

Gracias a @ user23013 por guardar 3 bytes.

Pruébalo en línea aquí


Desde el OP, "Este es un desafío de manipulación de matriz, no un desafío de manipulación de cadenas".
atk

@atk: es discutible ya que OP solo rechaza explícitamente la expresión regular.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Abreviatura de /La-: %.
jimmy23013

@ user23013 ¡Guau, nunca se molestó en darse cuenta de que también %es para dividir, y también se divide en múltiples ocurrencias!
Optimizador

@atk Sí, ya que solo se prohibieron las expresiones regulares, utilicé esta técnica.
Optimizador

25

JavaScript, ES6, 44 bytes

f=(a,b,i=0)=>a.map(x=>x.map?f(x,b,i):b[i++])

Esto crea una función fque se puede llamar como

f([0,[1,[]],[[]],[2,3],[]],[1,6,1,8])

es decir, la matriz anidada y la matriz de valores como argumentos de entrada. La salida de la función es la matriz anidada convertida.

Esta pregunta es una muy buena pregunta para la recursividad, es por eso que la respuesta es una función de recursión ordenada y dulce. Creo una función fque convierte el primer argumento usando el mapmétodo Para cada elemento, si el elemento es una matriz, llama fde nuevo, de lo contrario, para los números enteros, se pone el i º elemento y rendimientos que, incrementando el valor de i. El valor de ise transmite en cada llamada recursiva, para mantener el orden correcto.

La detección de matriz vs. entero se realiza nuevamente utilizando el mapmétodo. Para una variable de matriz, mapes una función válida, mientras que para las variables enteras, no hay ninguna propiedad o función llamada mapdefinida para la variable.

Esto funciona en un navegador Firefox más reciente (debido a ES6).


3
Sé que debería evitar comentarios como "+1" y "gracias", pero ¡maldita sea, esta es una dulce función de ES6! Puedo mirar esta línea de código durante horas :)
Jacob

Creo que hay 2 .mapen el código. ¿Hay alguna forma de acortarlo aún más? De todos modos, buen código!
Derek 朕 會 功夫

Vaya, ¿cuándo agregó ES esa sintaxis lambda?
esponjoso

@fluffy en ES6;)
Optimizer

@Derek 朕 會 功夫 desafortunadamente no. mapestá vinculado al contexto, por lo que el primer mapa pertenece amientras que el siguiente mapa pertenece a cada uno xen la iteración. No hay otra forma más corta de referirse map, ni de diferenciar la matriz de los enteros
Optimizer el

18

JavaScript, ES6, 41 bytes

La respuesta de Optimizer me impresionó mucho , fue muy inteligente y aprendí mucho. Sin embargo, al mirarlo, encontré una forma de acortarlo un poco y corregir un pequeño error:

f=(a,b)=>a.map(x=>x.map?f(x,b):b.shift())

Saqué la ivariable y la reemplacé con a shift(). Esto lo hace un poco más corto y soluciona el problema con el hecho de que ise pasa por valor y no por referencia, lo que hace que algunos números de la matriz final se repitan y otros al final no se usen. Una vez más, la respuesta de Optimizer fue muy bien pensada, mejor de lo que podría haberlo hecho, solo la arreglé un poco.


2
Buen golf! Un poco triste porque no entendí eso: P
Optimizer

16

Dyalog APL, 14 caracteres

Esto es una obviedad: (∊a)←b.

Normalmente, ∊asignifica aaplanado, pero cuando ocurre en el lado izquierdo de una tarea, hace precisamente lo que está pidiendo este problema. Para cumplir con el requisito de ser una función, necesita algunos garabatos adicionales: {a←⍺⋄(∊a)←⍵⋄a}(llaves para lambda; y para argumento izquierdo y derecho; para separador de enunciados).

Prueba en tryapl.org. Tenga en cuenta que en APL el vector numérico vacío se denota por ("zilde"). Los vectores de un elemento se construyen con (,A)porque (A)significaría un escalar. En la salida, esto:

┌⊖┐
│0│
└~┘

representa un vector numérico vacío El 0en el centro muestra el "elemento prototípico" que no es un elemento de la matriz.


1
¿Esa representación gráfica no distingue (,1)y (1)por qué el bit final se presenta como en [1|1]lugar de [1|[1]]?
Martin Ender

La representación gráfica que usa tryapl (conocida como ]box on) no distingue entre ellos. Hay otra función en Dyalog ( displaydesde dfns.dws) que hace una distinción, pero desafortunadamente tryapl restringe la carga de espacios de trabajo adicionales (es decir, bibliotecas). :(
ngn

1
Para ver el resultado en forma de corchetes, intente lo siguiente: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(∇¨⍵)']'}a. O esto: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(1↓,'|',[1.5]∇¨⍵)']'}asi usted insiste en el separador, |.
ngn

Oh, también puedes usar ]display aen tryapl. Da información completa sobre la estructura. Lo siento, no me di cuenta de esto al principio.
ngn

Punto justo. Lo convertí en una función a costa de 2 bytes adicionales.
ngn

10

Python, 51

f=lambda a,b:[b.pop(0)if x<[]else f(x,b)for x in a]

Ejemplo:

>>> f([0,[1,[]],[[]],[2,3],[]], [1,6,1,8])
[1, [6, []], [[]], [1, 8], []]

10

Pitón 2, 50

f=lambda s,v:v.pop(0)if s<[]else[f(x,v)for x in s]

Este fue un problema muy hermoso. Mientras seguía trabajando en ello, me di cuenta de que los bits de mi código eran innecesarios, y la lógica colapsó en una expresión simple. La mayor parte del golf estaba en encontrar el algoritmo correcto.

ses la estructura y ves la lista plana de la lista. La idea es verificar si ses un número entero con s<[](Python 2 trata los números como más pequeños que las listas). Si es así, simplemente tome y devuelva el primer elemento de v, eliminándolo v. De lo contrario, recurrir a las sublistas de s.

El pop es una pieza de magia imperativa en un código de estilo muy funcional. Como todos vapuntan a la misma instancia, extraer un elemento de uno lo elimina de vtodo el árbol de ejecución, por lo que cada número vsolo se usa una vez. La comprensión de la lista [f(x,v)for x in s]crea un árbol de llamadas que se expande primero en profundidad y de izquierda a derecha, lo que hace que los elementos vse coloquen en el orden correcto.

Escribí esto independientemente de la respuesta de grc , pero resultó ser lo mismo hasta mover un solo [(y nombres de variables). El movimiento ahorra un char debido al espaciado. El movimiento de soporte significa manejar el caso de nodo inmediatamente en la función, en lugar de como parte de la comprensión de la lista, lo que no había considerado.

Podemos guardar un carácter para 49 si ampliamos los requisitos de entrada para tomar el valor de STDIN y la estructura como un argumento de función. Esto nos permite usar map.

v=input()
g=lambda s:v.pop(0)if s<[]else map(g,s)

9

Ruby, 39

f=->a,b{a.map{|d|f[d,b]}rescue b.shift}

Se repite hasta que el elemento en la lista es un número entero.
Como llamar a Integer.map da una excepción,
va a la parte de rescate, que "muestra / desplaza" el primer elemento de la segunda lista.

Regex soln ... un poco más:

f=->a,b{eval a.to_s.split(/\d+/).zip(b)*''}

Pruébalo con algunos casos de prueba


Solo como referencia, las soluciones de expresiones regulares no están permitidas. ;)
Martin Ender

5

CJam, 43 37 35 33 bytes

Esta es una conversión directa de mi respuesta JS . Un poco largo, la mayoría de los cuales está ocupado por la detección de tipo.

q~:B;{{_`La`&{F}{;BW):W=}?}%}:F~`

Toma las dos matrices de entrada en dos líneas de STDIN como

[[[1 3] 2] [1 4] 12 [] [[0 0] [5 [7]]]]
[1 1 0 1 0 0 0 0 1 1]

y salidas a STDOUT como

[[[1 1] 0] [1 0] 0 "" [[0 0] [1 [1]]]]

Pruébalo en línea aquí


5

Haskell, 113104 bytes (86 + 18 de la declaración de tipo de datos)

data N=I Int|L[N]
L[]!v=(L[],v)
L(a:b)!v|(c,w)<-a!v,(L d,u)<-L b!w=(L$c:d,u)
_!(n:m)=(I n,m)
s#v=fst$s!v

Haskell no tiene un tipo de datos de matriz anidada incorporado, por lo que tuve que rodar el mío. Por esta razón, el programa contiene solo coincidencia de patrones y recursividad estructural explícita. El último caso de prueba lee

L[I 0,L[I 1,L[]],L[L[]],L[I 2,I 3],L[]]#[1,6,1,8]

y evalúa a

L[I 1,L[I 6,L[]],L[L[]],L[I 1,I 8],L[]]

4

Mathematica, 41 bytes

Function[,m[[i++]],Listable][i=1;m=#2;#]&

Esta es una función sin nombre que toma la estructura como primer argumento y la lista de valores como segundo argumento (y devuelve una lista).

Esta es una versión de golf de la respuesta aceptada. sobre la pregunta que inspiró este desafío. Estoy publicando esto yo mismo, y no aceptaré esta respuesta (si en realidad sigue siendo la más corta, lo dudo). Esto es para evitar que alguien más gane el desafío copiando básicamente la respuesta.

Cómo funciona:

  • Definimos una Listablefunción pura. Las funciones de lista se aplican automáticamente a los elementos de un argumento de lista (recursivamente) en lugar de la lista en sí misma, por lo que llamar fa la lista estructurada básicamente devolverá una lista de la misma estructura con cada entero ireemplazado por f[i].
  • Almacenamos la lista de valores en el global my un contador en i.
  • Cada vez que llamamos f(independientemente del argumento) devolvemos el siguiente elemento de m.

4

Rebol - 87 66 60

f: func[a[block!]b][map-each n a[any[attempt[f n b]take b]]]

Sin golf:

f: func [a [block!] b] [
    map-each n a [
        any [
            attempt [f n b]  
            take b
        ]
    ]
]

Ejemplo:

>> f [0 [1 []] [[]] [2 3] []]   [1 6 1 8]           
== [1 [6 []] [[]] [1 8] []]

4

C #, 225 + 13 = 239185 + 35 = 220172 + 35 = 207 bytes

Requiere esto:

using System;using o=System.Object;

Acepta object[]s como argumentos.

o[]u(o[]a,o[]b){var c=a;int i=0;Action<o[],o[]>d=null;d=(e, f)=>{for(int j=0;j<e.Length;j++){if(e[j]is int){f[j]=b[i];i++;}else{d((o[])e[j],(o[])f[j]);}}};d(a,c);return c;}

Código sin golf:

object[] Unflatten(object[] structure, object[] values)
{
    var c = structure;
    int i = 0;
    Action<object[], object[]> recursiveFunc = null;
    recursiveFunc = (e, f) =>
    {
        for (int j = 0; j < e.Length; j++)
        {
            if (e[j] is int)
            {
                f[j] = values[i]; i++;
            }
            else
            {
                recursiveFunc((object[])e[j], (object[])f[j]);
            }
        }
    };
    recursiveFunc(structure, c);
    return c;
}

2
Puede acortarlo un poco más usando using o=System.Objecty reemplazando todas las instancias de objectsimplemente o. msdn.microsoft.com/en-us/library/sf0df423.aspx
Kroltan

1
@Kroltan Gran consejo, gracias!
ProgramFOX

Clonees poco profundo Si se permite la modificación de las entradas, no necesita clonar en absoluto. Si no está permitido, necesita una clonación adecuada.
CodesInChaos

@CodesInChaos ya veo. Como se permite modificar la matriz de entrada, eliminé el clon. ¡Gracias!
ProgramFOX

3

Python 2, 64 bytes

def g(N,L):f=lambda N:L.pop(0)if`N`<":"else map(f,N);return f(N)

Te escuché como listas en listas, así que puse funciones en funciones.

Editar: Al mirar la respuesta de grc ahora me doy cuenta de que era completamente innecesario. Oh bien...


3

SWI-Prolog 82

f([],A,[],A):-!.
f([H|T],A,[J|U],B):-(is_list(H),!,f(H,A,J,C);A=[J|C]),f(T,C,U,B).

Ejecución de muestra:

?- f([[[1,3],2],[1,4],12,[[0,[],0],[5,[7]]]],[1,1,0,1,0,0,0,0,1,1],R,[]).
R = [[[1,1],0],[1,0],0,[[0,[],0],[1,[1]]]].

El último []en la consulta es para verificar la cantidad de elementos que no coinciden, lo que no parece ser necesario en esta pregunta.


¿Qué hace que los recortes (y, por extensión, los costosos is_list) sean necesarios?
Cadena no relacionada

1
@UnrelatedString: siéntase libre de editar la respuesta directamente si la encuentra innecesaria para obtener la respuesta correcta. Mi Prolog era malo en aquel entonces (uso la biblioteca y los cortes extensivamente) y aún más oxidado en estos días.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

2

Erlang, 116 93 Bytes

f(R,F)->put(n,F),[g(X)||X<-R].
g([H|T])->[g(H)|g(T)];g([])->[];g(E)->[H|T]=get(n),put(n,T),H.

Utiliza dos funciones impuras fy g. fmanipula el diccionario de procesos estableciendo nla lista plana y asigna cada elemento de la lista anidada a g(X). gluego se establece nen la cola de la lista plana cada vez que encuentra un valor que no es de la lista y devuelve el encabezado de la lista plana.


1

Perl 5, 49 bytes

El primer argumento es la estructura de la plantilla, el segundo son los valores.

sub u{($t,$l)=@_;ref$t?[map{u$_,$l}@$t]:shift@$l}

Programa de prueba

use Test::More;
use Test::Deep;

sub u{($t,$l)=@_;ref$t?[map{u$_,$l}@$t]:shift@$l}

cmp_deeply u([[[1,3],2],[1,4],12,[[0,0],[5,[7]]]],[1,1,0,1,0,0,0,0,1,1]),[[[1,1],0],[1,0],0,[[0,0],[1,[1]]]];
cmp_deeply u([[[0,0],0],[0,0],0,[[0,0],[0,[0]]]],[1,1,0,1,0,0,0,0,1,1]),[[[1,1],0],[1,0],0,[[0,0],[1,[1]]]];
cmp_deeply u([], []), [];
cmp_deeply u([[]], []), [[]];
cmp_deeply u([0,1,2,3], [5,1,0,5]), [5,1,0,5];
cmp_deeply u([[[[[0]]]]], [123]), [[[[[123]]]]];
cmp_deeply u([0,[1,[]],[[]],[2,3],[]], [1,6,1,8]), [1,[6,[]],[[]],[1,8],[]];
done_testing;

1

Powershell: 115

la matriz de entrada es $ i, la asignación es $ m, la salida es $ o

$h={if($_.GetType().IsArray){if($_.c -eq 0){,@()}else{,@($_|%{.$h})}}else{$m[$c++]}};$i|%{$o=@();$c=0}{$o+=,(.$h)}

$ h es una cadena que contiene la función recursiva, y puede ejecutar el código contenido en una cadena con. $ h ... Y sería 30 bytes más corto si powershell no insistiera en aplanar matrices de valor único a escalares, y una matriz con un solo valor nulo a nulo

y un práctico visor de estructura de matriz para verificar resultados

$j={if($_.GetType().IsArray){write-host '(' -n;($_|%{.$j});write-host ')' -n}else{write-host "$_" -n}};write-host '(' -n;$o|%{(.$j)}; write-host ')' -n;

editar: 149

guardar como unflatten.ps1:

$m=[array]$args[1];$h={if($_.GetType().IsArray){if($_.c -eq 0){,@()}else{,@($_|%{.$h})}}else{$m[$c++]}};$args[0]|%{$o=@();$c=0}{$o+=,(.$h)};echo $o;

editar: 136, creación de matriz de salida en línea y escritura-salida

$m=[array]$args[1];$h={if($_.GetType().IsArray){if($_.c -eq 0){,@()}else{,@($_|%{.$h})}}else{$m[$c++]}};echo(,@($args[0]|%{$c=0}{.$h}))

llamar con. \ unflatten.ps1 [matriz de entrada] [matriz de mapeo]

la salida se escribe en la tubería, así que ejecute esto primero:

Function View-Array{
Param([Parameter(ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
      [array]$o)

    PROCESS{
    $j={if($_.GetType().IsArray){write-host '(' -n;($_|%{.$j});write-host ')' -n}else{write-host "$_" -n}};
    write-host '(' -n;$o|%{(.$j)}; write-host ')' -n;
    }
}

y correr con

.\unflatten.ps1 [input array] [mapping array] | View-Array

1

C #, (40 + 123) = 163 bytes O (67 + 81) = 148 bytes

C # sufre de su tipo estático y espacios de nombres largos aquí.

Método de matriz

Usando declaraciones:

using o=System.Object;using System.Linq;

Código:

o[] u(o[] x,o[] y){int i=0;Func<o[],o[],o[]> f=null;f=(a,b)=>a.Select(e=>e is int?b[i++]:f((o[])e,b)).ToArray();return f(x,y);}

Método de pila (utiliza la estructura de pila en lugar de matrices)

Usando declaraciones:

using s=System.Collections.Generic.Stack<object>;using System.Linq;

Código:

System.Func<s,s,s>f=null;f=(a,b)=>new s(a.Select(e=>e is int?b.Pop():f((s)e,b)));

Primeros intentos, primer código de golf aquí.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.