Dégraisser un tableau

34

Ce défi a été inspiré par une question sur Mathematica.SE .

Supposons que vous ayez une liste / un tableau imbriqué de structure quelconque (les listes à chaque niveau n'ont pas nécessairement la même longueur). Pour simplifier, supposons que les nœuds sont des entiers non négatifs ou des tableaux vides. Par exemple

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

Il est parfois plus pratique d’aplatir cette liste pour manipuler les nœuds, par exemple:

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

Mais à la fin, vous voulez réellement conserver la structure originale, donc vous voulez le transformer en

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

Votre tâche consiste à effectuer cette dernière étape.

À partir d’une liste imbriquée d’entiers non négatifs arbitraires, qui représente la structure souhaitée du résultat, et d’une liste à plat d’entiers non négatifs, qui représentent les valeurs souhaitées, remodelez la liste à plat sous la forme de la liste structurée. Vous pouvez supposer que les deux listes contiennent le même nombre d'entiers.

Comme d'habitude, vous n'avez pas à traiter d'entrées non valides (par exemple, la deuxième liste n'est pas plate, l'entrée est syntaxiquement mal formée, ne contient pas de nombres entiers comme nœuds, etc.). Vous pouvez modifier les tableaux d'entrée dans votre code.

Vous pouvez écrire une fonction ou un programme en prenant une entrée via STDIN, un argument de ligne de commande ou un argument de fonction, et vous pouvez renvoyer le résultat ou l’imprimer sur STDOUT. Vous pouvez utiliser n’importe quel format commode de liste ou de chaîne pour représenter les entrées et les sorties (tant que le format est sans ambiguïté et que l’entrée n’est pas prétraitée). De plus, le format des deux entrées doit être cohérent (vous ne pouvez donc pas prendre une entrée sous forme de chaîne et l'autre sous forme de liste, par exemple). Vous pouvez prendre les listes de saisie dans l’un ou l’autre des ordres, mais veuillez spécifier le mode de saisie exact dans votre réponse.

Encore une restriction: vous ne devez pas utiliser d'expressions régulières. C'est un défi de manipulation de tableau, pas un défi de manipulation de chaîne.

C'est le code de golf, donc la réponse la plus courte (en octets) gagne.

Cas de 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],[]]
Martin Ender
la source
Est-il autorisé si les valeurs du tableau Structure sont modifiées?
ProgramFOX le
@ ProgramFOX oui. "Vous pouvez modifier les tableaux d'entrée dans votre code."
Martin Ender
Ironiquement, une des soumissions ici est dans Mathematica.
Isiah Meadows
1
@impinball C'est le mien, que j'ai posté en même temps que la question, afin d'empêcher quiconque de voler la réponse à la question liée (et en fait, il ne s'agit que d'une version loupée de cette réponse).
Martin Ender
@ MartinBüttner Oh. Agréable. C'est aussi l'une des réponses les plus courtes.
Isiah Meadows

Réponses:

9

CJam, 18 16 13 octets

lA,sNerN%l~]z

Prend une entrée via STDIN dans le même format que la réponse CJam précédente:

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

et affiche la chaîne de résultat dans STDOUT

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

Je traite simplement la première ligne comme une chaîne, convertis tous les caractères numériques en sauts de ligne, scinde une ou plusieurs occurrences de sauts de ligne, place la seconde ligne sous forme de tableau sur pile, enroule un tableau et zippe les deux tableaux (lignes). L'impression est automatique et comme la première ligne a été traitée comme une chaîne, elle conserve ses crochets.

Expansion du code

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

Merci à @ user23013 pour la sauvegarde de 3 octets.

Essayez-le en ligne ici

Optimiseur
la source
Dans l'OP, "Il s'agit d'un défi de manipulation de tableau, pas d'un défi de manipulation de chaîne."
Atk
@atk: C'est discutable puisque OP n'interdit explicitement que les expressions régulières.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
1
Abréviation de /La-: %.
jimmy23013
@ user23013 Wow, je n'ai jamais pris la peine de me rendre compte que %c'est aussi pour la division, et qu'elle se divise en plusieurs occurrences aussi!
Optimiseur
@atk Oui, puisque seules les expressions rationnelles ont été interdites, j'ai utilisé cette technique.
Optimiseur
25

JavaScript, ES6, 44 octets

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

Cela crée une fonction fqui peut être appelée comme

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

c'est-à-dire le tableau imbriqué et le tableau de valeurs comme arguments d'entrée. La sortie de la fonction est le tableau imbriqué converti.

Cette question est une très bonne question pour la récursivité, c’est pourquoi la réponse est une fonction de récursion soignée et douce. Je crée une fonction fqui convertit le premier argument en utilisant la mapméthode. Pour chaque élément, si l'élément est un tableau, il appelle à fnouveau, sinon, pour les entiers, il obtient le i e point et revient que, incrémenter la valeur i. La valeur de iest transmise dans chaque appel récursif, afin de maintenir l'ordre correct.

La détection Array vs. Integer est à nouveau effectuée à l'aide de la mapméthode. Pour une variable de tableau, mapest une fonction valide, alors que pour les variables de nombre entier, il n’existe aucune propriété ou fonction appelée mapdéfinie pour la variable.

Cela fonctionne dans un dernier navigateur Firefox (en raison de ES6).

Optimiseur
la source
3
Je sais que je devrais éviter les commentaires tels que "+1" et "merci", mais bon sang c'est une douce fonction ES6! Je peux regarder cette ligne de code pendant des heures :)
Jacob
Je vois qu'il y en a 2 .mapdans le code. Y a-t-il un moyen de le raccourcir davantage? Quoi qu'il en soit, beau code!
Derek 會 功夫
Whoa, quand ES a-t-il ajouté cette syntaxe lambda?
moelleux
@ Fluffy dans ES6;)
Optimiseur
@Derek 朕 會 功夫 malheureusement non. mapest liée au contexte, donc la première carte appartient à, atandis que la carte suivante appartient à chacun xdans l'itération. Il n'y a pas d'autre moyen plus court de se référer map, ni de différencier un tableau des entiers
Optimiseur
18

JavaScript, ES6, 41 octets

J'ai été très impressionné par la réponse d' Optimizer , elle était très bien faite et j'ai beaucoup appris. Cependant, en le regardant, j'ai trouvé un moyen de le raccourcir légèrement et de corriger un petit bug:

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

J'ai sorti la ivariable et l' ai remplacée par un shift(). Cela le rend légèrement plus court et corrige le problème avec le fait que ce paramètre iest passé par valeur et non par référence, ce qui a entraîné la répétition de certains nombres du tableau final et la non utilisation de certains. Encore une fois, la réponse d'Optimizer était vraiment bien pensée, mieux que ce que j'aurais pu faire, je viens de la corriger un peu.

skycon
la source
2
Beau golf! Un peu triste de ne pas avoir compris ça: P
Optimizer
16

Dyalog APL, 14 caractères

Ceci est une évidence: (∊a)←b.

Normalement, les ∊amoyens sont aaplatis, mais quand cela se produit à gauche d'une tâche, il fait exactement ce que ce problème demande. Pour se conformer à l'exigence d'être une fonction, il faut quelques gribouillis supplémentaires: {a←⍺⋄(∊a)←⍵⋄a}(accolades pour lambda; et pour les arguments left et right; pour statement separator).

Testez sur tryapl.org. Notez que dans APL, le vecteur numérique vide est noté ("zilde"). Les vecteurs à un élément sont construits avec (,A)car (A)signifierait un scalaire. Dans la sortie, cette chose:

┌⊖┐
│0│
└~┘

représente un vecteur numérique vide. Le 0dans le centre montre "l’élément prototype" qui n’est pas un élément du tableau.

ngn
la source
1
Cette représentation graphique ne distingue-t-elle pas (,1)et (1)ou pourquoi le dernier bit vient-il simplement [1|1]de [1|[1]]?
Martin Ender
La représentation graphique que tryapl utilise (connue sous le nom de ]box on) ne fait pas de distinction entre eux. Dyalog ( displayfrom dfns.dws) a une autre fonction qui fait la distinction, mais malheureusement tryapl limite le chargement d'espaces de travail supplémentaires (c'est-à-dire des bibliothèques). :(
ngn
1
Pour voir le résultat sous forme entre crochets, essayez ceci: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(∇¨⍵)']'}a. Ou ceci: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(1↓,'|',[1.5]∇¨⍵)']'}asi vous insistez sur le séparateur, |.
ngn
Oh, vous pouvez également utiliser ]display atryapl. Il donne des informations complètes sur la structure. Désolé, je n'avais pas compris cela au début.
ngn
Bon point. Je l'ai transformé en une fonction au prix de 2 octets supplémentaires.
ngn
10

Python, 51

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

Exemple:

>>> f([0,[1,[]],[[]],[2,3],[]], [1,6,1,8])
[1, [6, []], [[]], [1, 8], []]
grc
la source
10

Python 2, 50

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

C'était un très beau problème. Tandis que je continuais à travailler dessus, je continuais à réaliser que des morceaux de mon code étaient inutiles et que la logique était réduite à une simple expression. La majeure partie du golf consistait à trouver le bon algorithme.

sest la structure et vest la liste plate de la liste. L'idée est de vérifier si sest un entier avec s<[](Python 2 considère que les nombres sont plus petits que les listes). Si c'est le cas, prenez et retournez le premier élément de v, en le supprimant v. Sinon, revenez sur les sous-listes de s.

Le pop est un morceau de magie impératif dans le code de style très fonctionnel. Parce que tous vpointent vers la même instance, le fait de supprimer un élément d'un élément le supprime de vl'ensemble de l'arborescence d'exécution. Ainsi, chaque nombre vn'est utilisé qu'une seule fois. La compréhension de la liste [f(x,v)for x in s]crée un arbre d’appel qui est développé en profondeur d’abord et de gauche à droite, ce qui provoque lav dans le bon ordre.

J'ai écrit ceci indépendamment de la réponse de grc , mais il s'est avéré être le même jusqu'à déplacer un seul[ (et des noms de variables). Le mouvement enregistre un caractère en raison de l'espacement. Le déplacement du crochet signifie que le cas du nœud est traité immédiatement dans la fonction, plutôt que dans le cadre de la compréhension de la liste, ce que je n’avais pas envisagé.

Nous pouvons enregistrer un caractère pour 49 si nous étendons les exigences d'entrée pour prendre la valeur de STDIN et la structure en tant qu'argument de fonction. Cela nous permet d'utiliser map.

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

Ruby, 39 ans

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

Rechute jusqu'à ce que l'élément dans la liste soit un entier.
Étant donné que l'appel de Integer.map donne une exception,
il va à la partie de secours, qui "saute / décale" le premier élément de la deuxième liste.

Regex soln ... un peu plus longtemps:

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

Essayez-le avec quelques cas de test

Vectorisé
la source
Juste pour référence, les solutions regex ne sont pas autorisées. ;)
Martin Ender
5

CJam, 43 37 35 33 octets

Celui-ci est une conversion directe de ma réponse JS . Un peu long, dont la plupart est absorbée par la détection de type.

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

Prend les deux tableaux d’entrée sur deux lignes de STDIN comme

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

et les sorties à STDOUT comme

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

Essayez-le en ligne ici

Optimiseur
la source
5

Haskell, 113 104 octets (86 + 18 à partir de la déclaration de type de données)

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 n'a pas de type de données de tableau imbriqué intégré, j'ai donc dû rouler le mien. Pour cette raison, le programme contient uniquement une correspondance de modèle et une récursion structurelle explicite. Le dernier cas de test lit

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

et évalue à

L[I 1,L[I 6,L[]],L[L[]],L[I 1,I 8],L[]]
Zgarb
la source
4

Mathematica, 41 octets

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

Il s'agit d'une fonction non nommée qui prend la structure comme premier argument et la liste de valeurs comme second argument (et renvoie une liste).

Ceci est une version ludique de la réponse acceptée à la question qui a inspiré ce défi. Je poste ceci moi-même, et n'accepterai pas cette réponse (si elle reste la plus courte, j'en doute). C’est pour empêcher tout le monde de remporter le défi en copiant la réponse.

Comment ça marche:

  • Nous définissons une Listablefonction pure. Les fonctions listables sont automatiquement appliquées aux éléments d'un argument de liste (de manière récursive) au lieu de la liste elle-même; l'appel fà la liste structurée renverra donc une liste de la même structure avec chaque entier iremplacé f[i].
  • Nous stockons la liste de valeurs dans le global met un compteur dans i.
  • Chaque fois que nous appelons f(quel que soit l'argument), nous retournons l'élément suivant de m.
Martin Ender
la source
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
        ]
    ]
]

Exemple:

>> f [0 [1 []] [[]] [2 3] []]   [1 6 1 8]           
== [1 [6 []] [[]] [1 8] []]
draegtun
la source
4

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

Requiert ceci:

using System;using o=System.Object;

Accepte object[]s comme arguments.

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

Code non 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;
}
ProgramFOX
la source
2
Vous pouvez le raccourcir un peu plus en utilisant using o=System.Objectet en remplaçant toutes les instances de objectsimplement o. msdn.microsoft.com/en-us/library/sf0df423.aspx
Kroltan le
1
@Kroltan Excellent conseil, merci!
ProgramFOX le
Cloneest peu profonde. Si la modification des entrées est autorisée, vous n'avez pas besoin de cloner du tout. Si ce n'est pas autorisé, vous avez besoin d'un clonage approprié.
CodesInChaos
@CodesInChaos je vois. Comme la modification du tableau d'entrée est autorisée, j'ai supprimé le clone. Merci!
ProgramFOX
3

Python 2, 64 octets

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

Je vous ai entendu comme des listes dans des listes, alors je mets des fonctions dans des fonctions.

Edit: En regardant la réponse de grc maintenant, je me rends compte que c'était complètement inutile. Tant pis...

Sp3000
la source
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).

Échantillon échantillon:

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

Le dernier []élément de la requête permet de vérifier le nombre d'éléments non concordants, ce qui ne semble pas être nécessaire dans cette question.

n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
la source
Qu'est-ce qui rend les coupes (et par extension les plus coûteuses is_list) nécessaires?
Unrelated String
1
@UnrelatedString: N'hésitez pas à modifier directement la réponse si vous les avez trouvés inutiles pour obtenir la bonne réponse. Mon Prolog était mauvais à l’époque (j’utilise la bibliothèque et je coupe beaucoup) et encore plus rouillé de nos jours.
nh̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳
2

Erlang, 116 93 octets

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.

Utilise deux fonctions impures fet g. fmanipule le dictionnaire de processus en définissant nla liste à plat et en mappant chaque élément de la liste imbriquée g(X). gpuis définit nà la fin de la liste à plat chaque fois qu'il rencontre une valeur non listée et renvoie la tête de la liste à plat.

cPu1
la source
1

Perl 5, 49 octets

Le premier argument est la structure du modèle, le second les valeurs.

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

Programme de 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;
Hobbs
la source
1

Powershell: 115

le tableau d'entrée est $ i, le mappage est $ m, la sortie est $ o

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

$ h est une chaîne contenant la fonction récursive, et vous pouvez exécuter le code contenu dans une chaîne avec. $ h ... Et ce serait plus court de 30 octets si powershell n'insistait pas pour aplatir les tableaux à valeur unique en scalaires, et un tableau avec une seule valeur null à null

et un visualiseur de structure de tableau pratique pour vérifier les résultats

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

modifier: 149

enregistrer sous 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;

edit: 136, création de tableau en ligne et écriture en sortie

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

appel avec. \ unflatten.ps1 [tableau d'entrée] [tableau de mappage]

la sortie est écrite dans le pipeline - alors lancez ceci en premier:

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

et courir avec

.\unflatten.ps1 [input array] [mapping array] | View-Array
Ben
la source
1

C #, (40 + 123) = 163 octets OU (67 + 81) = 148 octets

C # souffre de son typage statique et de ses longs espaces de noms.

Méthode de tableau

Utiliser des déclarations:

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

Code:

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éthode Stack (utilise la structure Stack au lieu de tableaux)

Utiliser des déclarations:

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

Code:

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

Premiers essais, premier code golf ici.

Justin Dunlap
la source