Скасувати масив


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

Чи дозволено, якщо значення в масиві Структура змінюються?
ProgramFOX

@ProgramFOX так. "Ви можете змінити вхідні масиви у своєму коді."
Мартін Ендер

За іронією долі, одне із поданих тут матеріалів у Mathematica.
Ісія Медоуз

1
@impinball Це моє, що я розмістив разом із запитанням, щоб не допустити, щоб хто-небудь інший не вкрав відповідь із пов'язаного питання (а насправді це лише версія, що відповідає на цю гру).
Мартін Ендер

@ MartinBüttner О. Приємно. Це насправді одна з коротших відповідей.
Ісія Медоуз

Відповіді:


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 байтів.

Спробуйте його онлайн тут


В ОП "Це виклик маніпулювання масивом, а не виклик рядкових маніпуляцій".
atk

@atk: Це сперечально, оскільки OP лише явно забороняє регулярне вираження.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

1
Скорочено /La-: %.
jimmy23013

@ user23013 Нічого не турбуючись зрозуміти, що %це також для розколу, і він також розпадається на кілька випадків!
Оптимізатор

@atk Так, оскільки тільки регекс був заборонений, я використав цю техніку.
Оптимізатор

25

JavaScript, ES6, 44 байти

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

Це створює функцію, fяку можна назвати подібною

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

тобто вкладений масив і масив значень як вхідні аргументи. Виведенням функції є перетворений вкладений масив.

Це питання є дуже приємним запитанням для рекурсії, тому відповідь - це акуратна і солодка функція рекурсії. Я створюю функцію, fяка перетворює перший аргумент за допомогою mapметоду. Для кожного елемента, якщо елемент є масивом, він викликає fзнову, інакше для цілих чисел він отримує i- й елемент і повертає це, збільшуючи значення i. Значення iпередається в кожному рекурсивному дзвінку, щоб підтримувати порядок правильним.

Виявлення масиву проти цілого числа знову робиться за допомогою mapметоду. Для змінної масиву mapє дійсною функцією, тоді як для цілих змінних немає властивості або функції, що називається mapдля змінної.

Це працює в останньому браузері Firefox (завдяки ES6).


3
Я знаю, що мені слід уникати коментарів, таких як "+1" і "спасибі", але чорт забирає, це одна солодка функція ES6! Я можу годинами дивитись на цей рядок коду :)
Яків

Я вважаю, що .mapв коді існує 2 . Чи є якийсь спосіб її ще коротше? У будь-якому випадку, приємний код!
Дерек 朕 會 功夫

Whoa, коли ES додав цей лямбда-синтаксис?
пухнастий

@fluffy в ES6;)
Оптимізатор

@Derek 朕 會 功夫 на жаль ні. mapприв’язаний до контексту, тому перша карта належить, aа наступна карта належить кожній xв ітерації. Немає іншого коротшого способу посилання mapабо розмежувати масив від цілих чисел
Оптимізатор

18

JavaScript, ES6, 41 байт

Мене дуже вразила відповідь оптимізатора , це було дуже спритно зроблено, і я багато чого навчився. Однак переглянувши це, я знайшов спосіб трохи зменшити його та виправити невелику помилку:

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

Я вийняв iзмінну і замінив її на shift(). Це робить його трохи коротшим і виправляє проблему з тим, що iпередається за значенням, а не за посиланням, відьма викликала повторення деяких цифр з остаточного масиву, а деякі в кінці не використовуються. Знову ж таки, відповідь оптимізатора була дійсно добре продумана, краще, ніж я міг би зробити, я лише трохи це зафіксував.


2
Гарний гольф! Трохи сумно, що я цього не зловив: P
Оптимізатор

16

Діалог APL, 14 символів

Це не легке завдання: (∊a)←b.

Зазвичай це ∊aозначає aсплюснутість, але коли вона виникає в лівій частині завдання, вона робить саме те, про що вимагає ця проблема. Щоб відповідати вимозі бути функцією, їй потрібно кілька зайвих викруток: {a←⍺⋄(∊a)←⍵⋄a}(фігурні дужки для лямбда; і для аргументу зліва і справа; для роздільника висловлювань).

Тест на tryapl.org. Зауважте, що в APL порожній числовий вектор позначається ("zilde"). Одноелементні вектори побудовані з (,A)тому, (A)що означало б скаляр. У висновку ця річ:

┌⊖┐
│0│
└~┘

являє собою порожній числовий вектор. У 0центрі зображено "прототипний елемент", який не є елементом масиву.


1
Хіба це графічне зображення не розрізняє (,1)і (1)чому кінцевий біт просто подається як [1|1]замість [1|[1]]?
Мартін Ендер

Графічне зображення, яке використовує триапл (відоме як ]box on), не розрізняє їх. У Dyalog ( displayвід dfns.dws) є ще одна функція, яка робить розрізнення, але, на жаль, tryapl обмежує завантаження додаткових робочих просторів (тобто бібліотек). :(
ngn

1
Для того, щоб побачити результат в квадратних дужках форми, спробуйте наступне: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(∇¨⍵)']'}a. Або це: ∊{0=⍴⍴⍵:⍕⍵ ⋄ '['(1↓,'|',[1.5]∇¨⍵)']'}aякщо ви наполягаєте на сепараторі |.
ngn

О, ви також можете використовувати ]display aв триапл. Це дає повну інформацію про структуру. Вибачте, я спочатку цього не усвідомив.
ngn

Справедливий пункт. Я перетворив його на функцію ціною 2 зайвих байтів.
ngn

10

Пітона, 51

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

Приклад:

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

10

Пітон 2, 50

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

Це була дуже красива проблема. Коли я продовжував працювати над цим, я постійно розумів, що біти мого коду непотрібні, а логіка перетворилася на просте вираз. Більша частина гольфу була у пошуку правильного алгоритму.

sє структурою і vє плоским списком списку. Ідея полягає у тому, щоб перевірити, чи sє ціле число s<[](Python 2 вважає числа меншими за списки). Якщо це так, просто візьміть і поверніть перший елемент v, видаливши його v. В іншому випадку повторно перейдіть до списків s.

Це pop фрагмент імперативної магії в дуже функціональному стилі. Оскільки всі vвказують на один і той же екземпляр, спливаючий елемент з одного видаляє його з vусього дерева виконання, тому кожне число в vвикористовується лише один раз. Зрозуміння списку [f(x,v)for x in s]створює дерево викликів, яке розгортається першою глибиною та зліва направо, внаслідок чого елементи vрозміщуються в правильному порядку.

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

Ми можемо зберегти знак на 49, якщо розтягнути вимоги до введення, щоб взяти значення з STDIN та структури як аргумент функції. Це дозволяє нам використовувати map.

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

9

Рубі, 39

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

Повторюється, поки елемент у списку не буде цілим числом.
Оскільки виклик Integer.map дає виняток,
він переходить до рятувальної частини, яка "вискакує / зміщує" 1-й елемент із 2-го списку.

Regex soln ... трохи довше:

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

Спробуйте це в деяких тестових випадках


Тільки для довідки, рішення для регулярних виразів заборонені. ;)
Мартін Ендер

5

CJam, 43 37 35 33 байт

Це пряме перетворення моєї відповіді JS . Трохи довга, більшість з яких займається виявленням типу.

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

Бере два вхідні масиви на двох рядках STDIN, як

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

і виводи в STDOUT як

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

Спробуйте його онлайн тут


5

Haskell, 113 104 байт (86 + 18 від декларації типу даних)

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 немає вбудованого типу вкладених масивів масиву, тому мені довелося згорнути свій власний. З цієї причини програма містить лише відповідність шаблонів і явну структурну рекурсію. Читається останній тестовий випадок

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

і оцінює до

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

4

Математика, 41 байт

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

Це неназвана функція, яка приймає структуру як перший аргумент, а список значень як другий аргумент (і повертає список).

Це гольф-версія прийнятої відповіді на питання, яке надихнуло це завдання. Я публікую це сам, і не прийму цю відповідь (якщо вона насправді залишатиметься найкоротшою, у чому я сумніваюся). Це робиться для того, щоб хто-небудь інший не переміг у виклику, в основному скопіювавши відповідь.

Як це працює:

  • Визначимо Listableчисту функцію. Функції, що вибираються, автоматично застосовуються до елементів аргументу списку (рекурсивно) замість самого списку, тому виклик fу структурованому списку в основному поверне список тієї самої структури з кожним цілим числом, iзаміненим на f[i].
  • Ми зберігаємо список значень у глобальному mі лічильник у i.
  • Кожен раз, коли ми викликаємо f(незалежно від аргументу), ми повертаємо наступний елемент m.

4

Ребол - 87 66 60

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

Безголівки:

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

Приклад:

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

4

C #, 225 + 13 = 239 185 + 35 = 220 172 + 35 = 207 байт

Потрібно це:

using System;using o=System.Object;

Приймає object[]s як аргументи.

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

Невикористаний код:

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
Ви можете скоротити її трохи більше, використовуючи using o=System.Objectта замінюючи всі екземпляри objectпросто o. msdn.microsoft.com/en-us/library/sf0df423.aspx
Кролтан

1
@Kroltan Чудова порада, дякую!
ProgramFOX

Cloneнеглибокий. Якщо модифікація входів дозволена, клонувати взагалі не потрібно. Якщо це не дозволено, потрібно правильне клонування.
CodesInChaos

@CodesInChaos Я бачу. Оскільки допускається зміна вхідного масиву, я видалив клон. Спасибі!
ProgramFOX

3

Python 2, 64 байти

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

Я чув, як вам подобаються списки в списках, тому я ставлю функції у функції.

Правка: Переглядаючи відповідь grc зараз, я розумію, що це було зовсім непотрібно. Ну добре...


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

Проба зразка:

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

Останній []у запиті - це перевірка наявності невідповідної кількості елементів, що, здається, не потрібне в цьому питанні.


Що робить скорочення (і, як правило, дорогими is_list) необхідними?
Непов’язана струна

1
@UnrelatedString: Не соромтесь редагувати відповідь безпосередньо, якщо ви вважаєте їх непотрібними для отримання правильної відповіді. Мій Prolog тоді був поганий (я дуже часто користуюся бібліотекою та вирізаю) та ще більше іржавий.
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

2

Ерланг, 116 93 байт

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.

Використовує дві нечисті функції fі g. fманіпулює словником процесу, встановлюючи nплоский список і відображає кожен елемент вкладеного списку в g(X). gпотім встановлюється nв хвіст плоского списку кожного разу, коли він стикається зі значенням, яке не є списком, і повертає голову плоского списку.


1

Perl 5, 49 байт

Перший аргумент - структура шаблону, другий - значення.

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

Тестова програма

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

Потужність: 115

вхідний масив - $ i, відображення - $ m, вихід - $ o

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

$ h - рядок, що містить рекурсивну функцію, і ви можете виконувати код, що міститься в рядку з. з одним значенням null to null

і зручний переглядач структури масиву для перевірки результатів

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

правка: 149

зберегти як undelatten.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;

редагувати: 136, створення масиву вбудованого виводу та запису-виводу

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

дзвінок з. \ unlatten.ps1 [масив введення] [масив відображення]

вихід записується на конвеєр - тому запустіть це першим:

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

і бігти з

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

1

C #, (40 + 123) = 163 байт АБО (67 + 81) = 148 байт

C # страждає від свого статичного набору тексту та довгих просторів імен тут.

Метод масиву

Використання операторів:

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

Код:

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

Метод стека (використовує структуру стека замість масивів)

Використання операторів:

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

Код:

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

Перші спроби, перший код гольфу тут.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.