Раскрыть массив


34

Эта проблема была вдохновлена ​​вопросом о Mathematica.SE .

Скажем, у вас есть вложенный список / массив произвольной структуры (списки на каждом уровне не обязательно имеют одинаковую длину). Для простоты предположим, что узлы являются неотрицательными целыми числами или пустыми массивами. В качестве примера

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

Иногда более удобно сгладить этот список, чтобы выполнить некоторые манипуляции с узлами, например

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

Ваша задача - выполнить этот последний шаг.

При наличии вложенного списка произвольных неотрицательных целых чисел, который представляет желаемую структуру результата, и плоского списка неотрицательных целых чисел, которые представляют желаемые значения, преобразуйте плоский список в форму структурированного списка. Вы можете предположить, что оба списка содержат одинаковое количество целых чисел.

Как обычно, вам не нужно иметь дело с неверным вводом (например, второй список не является плоским, входные данные синтаксически искажены, не имеют целых чисел в качестве узлов и т. Д.). Вы можете изменить входные массивы в вашем коде.

Вы можете написать функцию или программу, используя ввод через STDIN, аргумент командной строки или аргумент функции, и вы можете вернуть результат или распечатать его в STDOUT. Вы можете использовать любой удобный список или строковый формат для представления ввода и вывода (при условии, что формат однозначен, а ввод не обработан заранее). Кроме того, формат обоих входов должен быть согласованным (например, вы не можете использовать один вход как строку, а другой как список). Вы можете использовать списки ввода в любом порядке, но, пожалуйста, укажите точный метод ввода в своем ответе.

Еще одно ограничение: вы не должны использовать регулярные выражения. Это задача манипулирования массивом, а не задача манипуляции со строками.

Это код гольф, поэтому самый короткий ответ (в байтах) выигрывает.

Тестовые случаи

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

Разрешено ли изменять значения в массиве Structure?
ProgramFOX

@ProgramFOX да. «Вы можете изменить входные массивы в вашем коде».
Мартин Эндер

По иронии судьбы, одно из представленных здесь материалов находится в Mathematica.
Исия Медоуз

1
@impinball Это моё, которое я разместил вместе с вопросом, чтобы не дать кому-либо украсть ответ на связанный вопрос (и на самом деле это всего лишь игра-ответ).
Мартин Эндер

@ MartinBüttner Ох. Ницца. Это на самом деле один из самых коротких ответов.
Isiah Meadows

Ответы:


9

CJam, 18 16 13 байтов

lA,sNerN%l~]z

Принимает ввод через STDIN в том же формате, что и предыдущий ответ CJam:

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

и выводит строку результата в STDOUT

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

Я просто трактую первую строку как строку, преобразую все цифровые символы в новые строки, разбиваю по одному или нескольким вхождениям новых строк, помещаю вторую строку как массив в стек, упаковываю в массив и объединяю два массива (строки). Печать выполняется автоматически и, поскольку первый ряд был обработан как строка, он сохраняет свои скобки.

Расширение кода

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

Спасибо @ user23013 за сохранение 3 байта.

Попробуйте онлайн здесь


From the OP, "This is an array manipulation challenge, not a string manipulation challenge."
atk

@atk: It is arguable since OP only explicitly disallow regular expression.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Short for /La-: %.
jimmy23013

@user23013 Wow, never bothered to realize that % is for split too, and it splits across multiple occurrences too!
Optimizer

@atk Yes, since only regex were banned, I used this technique.
Optimizer

25

JavaScript, ES6, 44 bytes

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

This creates a function f which can be called like

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

i.e. the nested array and the values array as input arguments. The output of the function is the converted nested array.

This question is a very nice question for recursion, that is why the answer is a neat and sweet recursion function. I create a function f which converts the first argument using the map method. For each element, if the element is an array, it calls f again, otherwise, for integers, it gets the ith item and returns that, incrementing the value of i. The value of i is passed down in each recursive call, so as to maintain the order correct.

Array vs. Integer detection is yet again done using the map method. For an array variable, map is a valid function, while for integer variables, there is no property or function called map defined for the variable.

This works in a latest Firefox browser (due to ES6).


3
I know I should avoid comments like "+1" and "thanks", but damn this is one sweet ES6 function! I can look at this code line for hours :)
Jacob

I se that there's 2 .map existed in the code. Is there any way to further shorten it? Anyway, nice code!
Derek 朕會功夫

Whoa, when did ES add that lambda syntax?
fluffy

@fluffy in ES6 ;)
Optimizer

@Derek朕會功夫 unfortunetely no. map is tied to the context, so the first map belongs to a while the next map belongs to each x in the iteration. There is no other shorter way to refer map either, nor to differentiate array from integers
Optimizer

18

JavaScript, ES6, 41 bytes

I was really impressed by Optimizer's answer, it was very cleverly done and I learned a lot. However on looking it over I found a way of shortening it slightly and fixing a small bug:

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

I took out the i variable and replaced it with a shift(). This makes it slightly shorter and fixes the problem with the fact that i is passed by value and not by reference, witch caused some numbers from the final array to repeat and some at the end not to be used. Again, Optimizer's answer was really well thought out, better than I could have done, I just fixed it a little.


2
Nice golf! A bit sad that I did not catch that :P
Optimizer

16

Dyalog APL, 14 characters

This is a no-brainer: (∊a)←b.

Normally, ∊a means a flattened, but when it occurs on the left-hand side of an assignment, it does precisely what this problem is asking for. To comply with the requirement of being a function, it needs a few extra squiggles: {a←⍺⋄(∊a)←⍵⋄a} (curly braces for lambda; and for left and right argument; for statement separator).

Test on tryapl.org. Note that in APL the empty numeric vector is denoted by ("zilde"). One-element vectors are constructed with (,A) because (A) would mean a scalar. In the output, this thing:

┌⊖┐
│0│
└~┘

represents an empty numeric vector. The 0 in the centre shows the "prototypical element" which is not an element of the array.


1
Does that graphical representation not distinguish (,1) and (1) or why is the final bit just presented as [1|1] instead of [1|[1]]?
Martin Ender

The graphical representation that tryapl uses (known as ]box on) doesn't distinguish between them. There's another function in Dyalog (display from dfns.dws) that does make a distinction, but unfortunately tryapl restricts the loading of additional workspaces (i.e. libraries). :(
ngn

1
To see the result in square-bracketed form, try this: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(∇¨⍵)']'}a. Or this: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(1↓,'|',[1.5]∇¨⍵)']'}a if you insist on the separator, |.
ngn

Oh, you can also use ]display a in tryapl. It gives complete information about the structure. Sorry, I didn't realize this at first.
ngn

Fair point. I turned it into a function at the cost of 2 extra bytes.
ngn

10

Python, 51

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

Example:

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

This was a very beautiful problem. As I kept working on it, I kept realizing that bits of my code were unnecessary, and the logic collapsed into a simple expression. Most of the golfing was in finding the right algorithm.

s is the structure and v is the flat list of list. The idea is to check whether s is an integer with s<[] (Python 2 treats numbers as smaller than lists). If it is, simply take and return the first element of v, removing it from v. Otherwise, recurse down onto the sublists of s.

The pop is a piece of imperative magic in very functional-style code. Because all v point to the same instance, popping an element from one removes it from v in the whole execution tree, so each number in v is only used once. The list comprehension [f(x,v)for x in s] creates a call tree that is expanded depth-first and left-to-right, causing the elements of v to be slotted in the correct order.

I wrote this independently of grc's answer, but it turned out to the same up to moving a single [ (and variable names). The move saves a char due to spacing. The bracket move means handling the node case immediately in the function, rather than as part of the list comprehension, which I hadn't considered.

We can save a char for 49 if we stretch the input requirements to take the value from STDIN and the structure as a function argument. This lets us use 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}

Recurses till the element in the list is an integer.
Since calling Integer.map gives an exception,
it goes to the rescue portion, which "pops/shift" the 1st element out of the 2nd list.

Regex soln... a bit longer:

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

Try it with some test cases


Just for reference, regex solutions aren't allowed. ;)
Martin Ender

5

CJam, 43 37 35 33 bytes

This one is a direct conversion of my JS answer. A bit long, most of which is taken up by type detection.

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

Takes the two input arrays on two lines of STDIN like

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

and outputs to STDOUT like

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

Try it online here


5

Haskell, 113 104 bytes (86 + 18 from datatype declaration)

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 does not have a built-in nested array datatype, so I had to roll my own. For this reason, the program contains only pattern matching and explicit structural recursion. The last test case reads

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

and evaluates to

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;#]&

This is an unnamed function which takes the structure as the first argument and the list of values as the second argument (and returns a list).

This is a golfed version of the accepted answer on the question that inspired this challenge. I'm posting this myself, and will not accept this answer (should it actually remain the shortest, which I doubt). This is in order to prevent any one else from winning the challenge by basically copying the answer.

How it works:

  • We define a Listable pure function. Listable functions are automatically applied to the elements of a list argument (recursively) instead of the list itself, so calling f on the structured list will basically return a list of the same structure with each integer i replaced by f[i].
  • We store the value list in the global m and a counter in i.
  • Each time we call f (regardless of the argument) we return the next element of 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
        ]
    ]
]

Example:

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

4

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

Requires this:

using System;using o=System.Object;

Accepts object[]s as 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;}

Ungolfed code:

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
You can shorten it a bit more by using using o=System.Object and replacing all instances of object with simply o. msdn.microsoft.com/en-us/library/sf0df423.aspx
Kroltan

1
@Kroltan Great tip, thanks!
ProgramFOX

Clone is shallow. If modification of the inputs is allowed, you don't need to clone at all. If it's not allowed, you need proper cloning.
CodesInChaos

@CodesInChaos I see. As modifying the input array is allowed, I removed the clone. Thanks!
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)

I heard you like lists in lists so I put functions in functions.

Edit: Looking at grc's answer now I realise that was completely unnecessary. Oh well...


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

Sample run:

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

The last [] in the query is for checking for mismatched number of elements, which doesn't seem to be necessary in this question.


What makes the cuts (and, by extension, the expensive is_list) necessary?
Unrelated String

1
@UnrelatedString: Feel free to edit the answer directly if you found them unnecessary to get the right answer. My Prolog was bad back then (I use library and cuts extensively) and even more rusty these days.
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.

Uses two impure functions f and g. f manipulates the process dictionary by setting n to the flat list and maps each element of the nested list to g(X). g then sets n to the tail of the flat list every time it encounters a non-list value and returns the head of the flat list.


1

Perl 5, 49 bytes

First argument is the template structure, second is the values.

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

Test Program

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

the input array is $i, the mapping is $m, output is $o

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

$h is a string containing the recursive function, and you can execute code contained in a string with .$h... And it would be 30 bytes shorter if powershell didn't insist on flattening single value arrays to scalars, and an array with a single null value to null

and a handy array structure viewer for verifying results

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

edit: 149

save as 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, inline output array creation and write-output

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

call with .\unflatten.ps1 [input array] [mapping array]

the output is written to the pipeline- so run this first:

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

and run with

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

1

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

C# suffers from its static typing and long namespaces here.

Array method

Using statements:

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

Stack method (uses the Stack structure instead of arrays)

Using statements:

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

First attempts, first code golf here.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.