Non appiattire una matrice


34

Questa sfida è stata ispirata da una domanda su Mathematica.SE .

Supponi di avere una lista / matrice nidificata di una struttura arbitraria (le liste di ogni livello non hanno necessariamente la stessa lunghezza). Per semplicità, supponiamo che i nodi siano numeri interi non negativi o array vuoti. Come esempio

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

A volte è più conveniente appiattire tale elenco per eseguire alcune manipolazioni dei nodi, ad es

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

Ma alla fine vuoi davvero preservare la struttura originale, quindi vuoi trasformarla in

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

Il tuo compito è eseguire l'ultimo passaggio.

Dato un elenco nidificato di numeri interi non negativi arbitrari, che rappresenta la struttura desiderata del risultato, e un elenco piano di numeri interi non negativi, che rappresentano i valori desiderati, rimodella l'elenco piano nella forma dell'elenco strutturato. Si può presumere che entrambi gli elenchi contengano lo stesso numero di numeri interi.

Come al solito, non è necessario gestire input non validi (ad es. Il secondo elenco non è piatto, l'input è sintatticamente malformato, non ha numeri interi come nodi, ecc.). È possibile modificare gli array di input nel proprio codice.

È possibile scrivere una funzione o un programma, prendendo input tramite STDIN, argomento della riga di comando o argomento della funzione, e si può restituire il risultato o stamparlo su STDOUT. È possibile utilizzare qualsiasi elenco o formato stringa conveniente per rappresentare l'input e l'output (purché il formato non sia ambiguo e l'input non sia preelaborato). Inoltre, il formato di entrambi gli input deve essere coerente (quindi non è possibile accettare un input come stringa e l'altro come elenco, ad esempio). Puoi prendere gli elenchi di input in entrambi gli ordini, ma specifica il metodo di input esatto nella tua risposta.

Un'altra limitazione: non devi usare espressioni regolari. Questa è una sfida di manipolazione di array, non una sfida di manipolazione di stringhe.

Questo è il golf del codice, quindi vince la risposta più breve (in byte).

Casi test

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],[]]

È consentito se i valori nell'array Structure vengono modificati?
Programma FOX

@ProgramFOX sì. "Puoi modificare le matrici di input nel tuo codice."
Martin Ender,

Ironia della sorte, una delle osservazioni qui è a Mathematica.
Isiah Meadows il

1
@impinball Questa è la mia, che ho pubblicato insieme alla domanda, al fine di impedire a chiunque altro di rubare la risposta alla domanda collegata (e in effetti, è semplicemente una versione ridotta di quella risposta).
Martin Ender,

@ MartinBüttner Oh. Bello. In realtà è anche una delle risposte più brevi.
Isiah Meadows il

Risposte:


9

CJam, 18 16 13 byte

lA,sNerN%l~]z

Accetta input tramite STDIN nello stesso formato della precedente risposta CJam:

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

e genera la stringa del risultato su STDOUT

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

Tratto semplicemente la prima riga come stringa, converto tutti i caratteri delle cifre in newline, divido su una o più occorrenze di newline, metto la seconda riga come un array in pila, avvolgo un array e comprimo i due array (righe). La stampa è automatica e poiché la prima riga è stata trattata come stringa, mantiene le parentesi.

Espansione del codice

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";

Grazie a @ user23013 per aver salvato 3 byte.

Provalo online qui


Dall'OP, "Questa è una sfida di manipolazione di array, non una sfida di manipolazione di stringhe".
atk

@atk: è discutibile dal momento che OP non consente esplicitamente l'espressione regolare.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Abbreviazione di /La-: %.
jimmy23013,

@ user23013 Wow, non si è mai preso la briga di capire che %è anche per la divisione e si divide anche in più occorrenze!
Ottimizzatore

@atk Sì, poiché solo i regex sono stati banditi, ho usato questa tecnica.
Ottimizzatore

25

JavaScript, ES6, 44 byte

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

Questo crea una funzione fche può essere chiamata come

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

vale a dire l'array nidificato e l'array dei valori come argomenti di input. L'output della funzione è l'array nidificato convertito.

Questa domanda è una domanda molto bella per la ricorsione, ecco perché la risposta è una funzione di ricorsione ordinata e dolce. Creo una funzione fche converte il primo argomento usando il mapmetodo. Per ogni elemento, se l'elemento è un array, chiama di fnuovo, altrimenti, per gli interi, ottiene l' ottavo elemento e lo restituisce, incrementando il valore di i. Il valore di iviene trasmesso in ogni chiamata ricorsiva, in modo da mantenere l'ordine corretto.

Il rilevamento di array e numeri interi viene ancora una volta eseguito utilizzando il mapmetodo Per una variabile di matrice, mapè una funzione valida, mentre per le variabili intere non esiste alcuna proprietà o funzione mapdefinita per la variabile.

Funziona con un browser Firefox più recente (grazie a ES6).


3
So che dovrei evitare commenti come "+1" e "grazie", ma dannazione questa è una dolce funzione ES6! Riesco a guardare questa riga di codice per ore :)
Jacob,

Vedo che .mapnel codice esistevano 2 . C'è un modo per accorciarlo ulteriormente? Comunque, bel codice!
Derek 功夫 會 功夫

Whoa, quando ES ha aggiunto quella sintassi lambda?
soffice

@fluffy in ES6;)
Ottimizzatore

@Derek 朕 會 功夫 purtroppo no. mapè legato al contesto, quindi la prima mappa appartiene a amentre la mappa successiva appartiene a ciascuna xnell'iterazione. Non esiste un altro modo più breve per fare riferimento map, né per differenziare l'array dagli interi
Optimizer

18

JavaScript, ES6, 41 byte

Sono stato davvero colpito dalla risposta di Optimizer , è stato fatto in modo molto intelligente e ho imparato molto. Tuttavia, osservandolo, ho trovato un modo per accorciarlo leggermente e correggere un piccolo bug:

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

Ho rimosso la ivariabile e l'ho sostituita con a shift(). Ciò lo rende leggermente più breve e risolve il problema con il fatto che iviene passato per valore e non per riferimento, in quanto alcuni numeri dell'array finale si ripetono e alcuni alla fine non vengono utilizzati. Ancora una volta, la risposta di Optimizer è stata davvero ben ponderata, meglio di quanto avrei potuto fare, l'ho appena risolto un po '.


2
Bel golf! Un po 'triste per non averlo scoperto: P
Ottimizzatore il

16

Dyalog APL, 14 personaggi

Questo è un gioco da ragazzi: (∊a)←b.

Normalmente ∊asignifica aappiattito, ma quando si verifica sul lato sinistro di un compito, fa esattamente ciò che questo problema richiede. Per soddisfare il requisito di essere una funzione, ha bisogno di alcuni scricchiolii extra: {a←⍺⋄(∊a)←⍵⋄a}(parentesi graffe per lambda; e per argomento sinistro e destro; per separatore di istruzioni).

Prova su tryapl.org. Si noti che in APL il vettore numerico vuoto è indicato da ("zilde"). I vettori a un elemento sono costruiti con (,A)perché (A)significherebbe uno scalare. Nell'output, questa cosa:

┌⊖┐
│0│
└~┘

rappresenta un vettore numerico vuoto. Il 0al centro mostra l '"elemento prototipo" che non è un elemento dell'array.


1
Quella rappresentazione grafica non distingue (,1)e (1)o perché il bit finale è appena presentato come [1|1]invece di [1|[1]]?
Martin Ender,

La rappresentazione grafica che Tryapl utilizza (noto come ]box on) non distingue tra di loro. C'è un'altra funzione in Dyalog ( displayda dfns.dws) che fa una distinzione, ma sfortunatamente tryapl limita il caricamento di aree di lavoro aggiuntive (ad es. Librerie). :(
ngn,

1
Per vedere il risultato in forma quadrata-parentesi, provate questo: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(∇¨⍵)']'}a. O questo: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(1↓,'|',[1.5]∇¨⍵)']'}ase ti ostini a separatore, |.
ngn,

Oh, puoi anche usarlo ]display ain tryapl. Fornisce informazioni complete sulla struttura. Scusa, all'inizio non me ne sono reso conto.
ngn,

Punto valido. L'ho trasformato in una funzione al costo di 2 byte extra.
ngn,

10

Python, 51

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

Esempio:

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

10

Python 2, 50

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

Questo è stato un problema bellissimo. Mentre continuavo a lavorarci su, continuavo a rendermi conto che frammenti del mio codice non erano necessari e che la logica si riduceva in una semplice espressione. Gran parte del golf era nella ricerca dell'algoritmo giusto.

sè la struttura ed vè l'elenco piatto dell'elenco. L'idea è di verificare se sè un numero intero con s<[](Python 2 considera i numeri più piccoli degli elenchi). In tal caso, è sufficiente prendere e restituire il primo elemento di v, rimuovendolo da v. Altrimenti, ricorrere nelle liste secondarie di s.

Il pop è un pezzo di magia imperativo in codice molto funzionale, in stile. Poiché tutti vpuntano alla stessa istanza, il pop-up di un elemento da uno lo rimuove vdall'intero albero di esecuzione, quindi ogni numero in vviene usato solo una volta. La comprensione dell'elenco [f(x,v)for x in s]crea un albero delle chiamate che viene espanso in profondità in primo luogo e da sinistra a destra, facendo sì che gli elementi di vvengano inseriti nell'ordine corretto.

Ho scritto questo indipendentemente dalla risposta di grc , ma si è rivelato lo stesso fino a spostare un singolo [(e nomi di variabili). La mossa salva un carattere a causa della spaziatura. Il movimento della parentesi significa gestire immediatamente il caso del nodo nella funzione, piuttosto che come parte della comprensione dell'elenco, che non avevo considerato.

Possiamo salvare un carattere per 49 se estendiamo i requisiti di input per prendere il valore da STDIN e la struttura come argomento di funzione. Questo ci permette di usare 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}

Recluta finché l'elemento nell'elenco non è un numero intero.
Poiché la chiamata a Integer.map fornisce un'eccezione,
si passa alla porzione di ripristino, che "apre / sposta" il primo elemento fuori dal secondo elenco.

Regex soln ... un po 'di più:

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

Provalo con alcuni casi di test


Solo per riferimento, le soluzioni regex non sono consentite. ;)
Martin Ender il

5

CJam, 43 37 35 33 byte

Questa è una conversione diretta della mia risposta JS . Un po 'lungo, la maggior parte dei quali è ripreso dal rilevamento del tipo.

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

Prende i due array di input su due righe di STDIN come

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

e trasmette a STDOUT come

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

Provalo online qui


5

Haskell, 113 104 byte (86 + 18 dalla dichiarazione del tipo di dati)

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 non ha un tipo di dati array nidificato incorporato, quindi ho dovuto implementare il mio. Per questo motivo, il programma contiene solo pattern matching ed esplicita ricorsione strutturale. Si legge l'ultimo caso di test

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

e valuta

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

4

Mathematica, 41 byte

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

Questa è una funzione senza nome che accetta la struttura come primo argomento e l'elenco di valori come secondo argomento (e restituisce un elenco).

Questa è una versione golfata della risposta accettata sulla domanda che ha ispirato questa sfida. Sto pubblicando questo da solo, e non accetterò questa risposta (se dovesse rimanere la più breve, di cui dubito). Questo al fine di impedire a chiunque altro di vincere la sfida, sostanzialmente copiando la risposta.

Come funziona:

  • Definiamo una Listablefunzione pura. Le funzioni elencabili vengono automaticamente applicate agli elementi di un argomento dell'elenco (in modo ricorsivo) anziché all'elenco stesso, quindi la chiamata fall'elenco strutturato restituirà sostanzialmente un elenco della stessa struttura con ogni numero intero isostituito da f[i].
  • Memorizziamo la lista valori nel globale me un contatore in i.
  • Ogni volta che chiamiamo f(indipendentemente dall'argomento) restituiamo il prossimo elemento di m.

4

Rebol - 87 66 60

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

Ungolfed:

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

Esempio:

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

4

C #, 225 + 13 = 239 185 + 35 = 220 172 + 35 = 207 byte

Richiede questo:

using System;using o=System.Object;

Accetta object[]s come argomenti.

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;}

Codice non golfato:

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
È possibile accorciare un po 'di più utilizzando using o=System.Objecte sostituendo tutte le istanze di objectcon semplice o. msdn.microsoft.com/en-us/library/sf0df423.aspx
Kroltan

1
@Kroltan Ottimo consiglio, grazie!
Programma FOX il

Cloneè poco profondo. Se è consentita la modifica degli input, non è necessario clonare affatto. Se non è consentito, è necessaria una corretta clonazione.
CodesInCos

@CodesInChaos vedo. Poiché è consentita la modifica dell'array di input, ho rimosso il clone. Grazie!
Programma FOX il

3

Python 2, 64 byte

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

Ho sentito che ti piacciono gli elenchi negli elenchi, quindi ho inserito le funzioni nelle funzioni.

Modifica: guardando la risposta di grc ora mi rendo conto che era completamente inutile. Oh bene...


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).

Esecuzione di esempio:

?- 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]]]].

L'ultimo []nella query è per verificare il numero di elementi non corrispondenti, che non sembra essere necessario in questa domanda.


Cosa rende necessari i tagli (e, per estensione, i costosi is_list)?
Unrelated String

1
@UnrelatedString: sentiti libero di modificare la risposta direttamente se non li hai trovati necessari per ottenere la risposta giusta. All'epoca il mio Prolog era cattivo (uso la biblioteca e taglia ampiamente) e ancora più arrugginito in questi giorni.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

2

Erlang, 116 93 byte

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.

Utilizza due funzioni impure fe g. fmanipola il dizionario di processo impostando nl'elenco piatto e mappa ogni elemento dell'elenco nidificato su g(X). gquindi imposta nla coda dell'elenco piatto ogni volta che incontra un valore non di elenco e restituisce la testa dell'elenco piatto.


1

Perl 5, 49 byte

Il primo argomento è la struttura del modello, il secondo è i valori.

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

Programma di test

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

l'array di input è $ i, il mapping è $ m, l'output è $ o

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

$ h è una stringa contenente la funzione ricorsiva e puoi eseguire il codice contenuto in una stringa con. $ h ... E sarebbe più corto di 30 byte se powershell non insistesse sull'appiattimento di array a valore singolo su scalari e un array con un singolo valore null su null

e un comodo visualizzatore di strutture di array per la verifica dei risultati

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

modifica: 149

salva come 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;

modifica: 136, creazione di array di output in linea e output di scrittura

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

chiama con. \ unflatten.ps1 [array di input] [array di mapping]

l'output viene scritto nella pipeline, quindi esegui prima questo:

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;
    }
}

e corri con

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

1

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

C # soffre della sua tipizzazione statica e dei lunghi spazi dei nomi qui.

Metodo di matrice

Utilizzando dichiarazioni:

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

Codice:

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);}

Metodo Stack (utilizza la struttura Stack anziché le matrici)

Utilizzando dichiarazioni:

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

Codice:

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

Primi tentativi, primo codice golf qui.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.