Масив викликів №2: відокремте вкладений масив


36

Примітка. Це номер 2 у ряді проблем . Для попереднього виклику натисніть тут .

Розділення вкладених списків

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

Тобто цей список:

[1, [2, 3], [4, 4, [5, 2], 1]]

Стають:

[1, [2], [3], [4], [4], [[5]], [[2]], [1]]

Змагання

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

Ви можете подати функцію, яка сприймає список як аргумент, або повну програму, яка виконує введення-виведення.

Оскільки це , виграє найкоротше (у байтах) *

* Стандартні лазівки для гольфу заборонені. Ви знаєте дриль.


Випробування

Списки введення містять лише цілі числа у стандартному цілому розмірі вашої мови. Щоб уникнути обмежень мов, які заважають їм конкурувати, значення не вкладаються на глибині більше 10.

Ви можете припустити, що вхідні дані не матимуть порожніх під-списків: наприклад - [[5, []]]не даватимуться. Однак основний список може бути порожнім.

[]            ->  []

[[1, 2]]      ->  [[1], [2]]
[3, [4, 5]]   ->  [3, [4], [5]]
[3, [3, [3]]] ->  [3, [3], [[3]]]
[[6, [[7]]]]  ->  [[6], [[[7]]]]
[[5, 10], 11] ->  [[5], [10], 11]

Не соромтесь залишити коментар, якщо я пропустив кутовий випадок.

Приклад

Я кинув разом швидкий (ungolfed) Python рішення 3 в Як приклад - ви можете перевірити його на repl.it .


Додайте контрольну скриньку з більшими за одноцифрові числа для відповідей на основі рядків.
orlp

@orlp хороша ідея.
FlipTack

2
Чи можемо ми припустити певну максимальну глибину? Скажи, 16?
orlp

@orlp Я скажу так, максимальна вкладена глибина буде 10, оскільки мене більше цікавить ваш алгоритм та виконання методу, ніж обмеження вашої мови. Зараз буде оновлено нитку.
FlipTack

Чи можу я вивести як рядок?
Rohan Jhunjhunwala

Відповіді:


4

Брахілог , 16 байт

:{##:0&:ga|g}ac|

Спробуйте в Інтернеті!

Пояснення

Example input: [1:[2:3]]

:{          }a     Apply the predicate below to each element of the list: [[1]:[[2]:[3]]]
              c    Concatenate: Output = [1:[2]:[3]]
               |   Or: Input = Output = []

  ##                 Input is a list: e.g. Input = [2:3]
    :0&              Call recursively the main predicate with this input: [2:3]
       :ga           Group each element in a list: Output = [[2]:[3]]
          |          Or (not a list): e.g. Input = 1
           g         Group into a list: Output = [1]

Що робить Zаргумент на TIO? Без цього це, здається, виводиться з true / false, що робить його, здається Z, необхідним у підрахунку байтів.
FlipTack

@FlipTack Zповідомляє Brachylog, що вихідний аргумент є змінною. Це ця змінна, яка об'єднується з отриманим результатом. Коли ви виймаєте його, він повідомляє Brachylog, що вихід є анонімною змінною, і замість цього надрукує, чи вдалий чи невданий головний предикат. Це те саме, що і в Prolog, де результат "ставиться" в змінну.
Фаталізувати

Добре :) приємна відповідь!
FlipTack

19

Математика, 24 21 байт

##&@@List/@#0/@#&/@#&

або один із них:

##&@@List/@#&/@#0/@#&
##&@@List@*#0/@#&/@#&
##&@@List/@#&@*#0/@#&

Пояснення

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

Тут багато синтаксичного цукру, тож почнемо з цього, щоб зняти гольф. &позначає з нього неназвану функцію, аргумент якої записаний як #. Всередині цієї функції #0посилається на саму функцію, яка дозволяє записувати неназвані рекурсивні функції. Але почнемо з того, щоб дати внутрішній функції назву та витягнути її:

f[x_] := ##& @@ List /@ f /@ x
f /@ # &

Інший важливий синтаксичний цукор - f/@xце короткий термін, Map[f, x]тобто він закликає fкожен елемент x. Причина f[x_] := ... f /@ xне призводить до нескінченної рекурсії в тому, що відображення чогось над атомом залишає атом незмінним, не фактично викликаючи функцію. Отже, нам не потрібно чітко перевіряти базовий регістр (поточний елемент - ціле число).

Таким чином, функція fспочатку повторюється вниз до найглибшого списку всередині x, і в цей момент вона f/@стає неоперативною . Тоді ми називаємо використання ##& @@ List /@цього. Картографування Listсписку просто загортає кожен елемент в окремий список, так {1, 2, 3}стає {{1}, {2}, {3}}. Тоді ми застосовуємо ##& до нього, що означає, що голова (тобто зовнішній список) замінюється ##&, і це перетворюється на ##&[{1}, {2}, {3}]. Але ##&просто повертає це аргументи як Sequence(що ви можете вважати розгорнутим списком або свого роду оператором "splat" іншими мовами).

Так ##& @@ List /@виходить список {1, 2, 3}в {1}, {2}, {3}(вид, що остання річ , насправді , загорнуті в голову Sequence, але, рівний нулю , як тільки ми використовуємо значення в будь-якому місці).

Це залишає питання, чому fсама по собі вже не є вирішенням проблеми. Проблема полягає в тому, що до зовнішнього списку слід по-різному трактуватись. Якщо у нас є вхід, {{1, 2}, {3, 4}}ми хочемо, {{1}, {2}, {3}, {4}}а ні {{1}}, {{2}}, {{3}}, {{4}} . Моє оригінальне рішення зафіксувало це, передавши кінцевий результат у вигляді списку аргументів, до Joinякого відновиться зовнішній рівень списків, але цей просто пропускає зовнішній рівень, використовуючи f себе у карті на виході. Отже, fвін застосовується лише до окремих елементів найвіддаленішого списку і ніколи не торкається цього списку.

Що стосується інших трьох рішень, то перший просто застосовує рекурсію, поза fякою працює так само добре. Інші два рішення уникають повторної Mapоперації, спочатку склавши дві функції, а потім відображаючи результат лише один раз.


8

J , 19 18 байт

(<@]/@,~>)S:0 1{::

Це анонімне дієслово, яке бере і повертає коробчасті масиви, які є J (досить громіздкою) версією вкладених масивів. Дивіться, що проходять усі тестові справи.

Пояснення

Для цього використовуються дещо екзотичні операції {::( карта ) та S:( розповсюдження ), які працюють на коробкових масивах. {::замінює кожен лист коробкою до цього аркуша. S:застосовує задане дієслово до заданої глибини вкладення, а потім розміщує результати в масив.

(<@]/@,~>)S:0 1{::  Input is y.
(        )          Let's look at this verb first.
        >           Open the right argument,
      ,~            append the left argument to it,
    /               then reduce by
 <@]                boxing. This puts the left argument into as many nested boxes
                    as the right argument is long.
                    This verb is applied to y
               {::  and its map
            0 1     at levels 0 and 1.
                    This means that each leaf of y is paired with its path,
                    whose length happens to be the nesting depth of y,
                    and the auxiliary verb is applied to them.
          S:        The results are spread into an array.

3

R, 199 байт

function(l){y=unlist(l);f=function(x,d=0){lapply(x,function(y){if(class(y)=='list'){f(y,d=d+1)}else{d}})};d=unlist(f(l));lapply(1:length(d),function(w){q=y[w];if(d[w]){for(i in 1:d[w])q=list(q)};q})}

Це питання було ТВОРДО. Списки R трохи дивні, і абсолютно непросто перебирати всі елементи списків. Потім не просто визначити глибину цього списку. Тоді викликом стає відтворити список з усіма розділеними елементами, тому нам також потрібен спосіб адаптивного створення списку певної глибини.

Рішення складається з двох великих частин. Рекурсивна функція, яка перетинає всі списки і записує глибину:

  f=function(x,d=0){
    lapply(x,function(y){
      if(class(y)=='list'){
        f(y,d=d+1)
      } else {
        d
      }})
  }

Коли ми маємо глибину кожного запису вектора unlist(l), що зберігається d, ми неявно створюємо список lapplyі заповнюємо його наступною функцією:

  lapply(1:length(d),function(w){
    q=y[w]
    if(d[w]){
      for(i in 1:d[w]){
        q=list(q)
      }
    }
    q
  })

У цьому застосуванні виклику ми створюємо об’єкт qзі значенням запису у списку, перевіряємо його глибину та бачимо, чи не є нульовим. Якщо він дорівнює нулю, ми можемо просто залишити його як числове значення. Якщо вона не дорівнює нулю, нам потрібно вкладати її в ту кількість списків. Таким чином, ми називаємо час-циклу dі неодноразово q=list(q).

lapplyпотім поміщає всі ці значення qу список, створюючи бажаний вихід.

Повна програма з правильним інтервалом і таке:

function(our.list){
  values <- unlist(our.list)
  f <- function(part.list, depth = 0){
    lapply(part.list, function(y){
      if(class(y)=='list'){
        f(y, depth <- depth + 1)
      } else {
        return(depth)
      }})
  }
  depths <- unlist(f(our.list))
  new.list <- lapply(1:length(depths), function(w){
    q <- values[w]
    if(depths[w] != 0){
      for(i in 1:depths[w]){
        q <- list(q)
      }
    }
    return(q)
  })
  return(new.list)
}

Приємно, це метод, який я використовував у своєму початковому рішенні Python для тестових випадків :)
FlipTack

is.list(y)замість class(y)=='list'? не може перевірити, що це насправді спрацює.
Джузеппе



2

C (gcc), 147 байт

d=0,l,i;
P(n,c){for(;n--;)putchar(c);}
main(c){for(;~(c=getchar());l=i)i=isdigit(c),P((l<i)*d,91),P(i,c),P((l>i)*d,93),P(l>i,32),d+=(92-c)*(c>90);}

Приклад введення:

1 [23 3] [40 4 [5 2] 1]

Приклад виводу:

1 [23] [3] [40] [4] [[5]] [[2]] [1]

2

складений , неконкурентний, 25 байт

{e d:e$wrap d 1-*}cellmap

Ця функція полягає в тому, що вона модифікує верхній член стека. Якщо ви хочете функцію сумлінного, просто додати [і ]на початку і в кінці. Спробуйте тут!

Ось прочитана версія:

{ arr :
  arr { ele depth :
    ele   $wrap depth 1- * (* execute wrap n times, according to the depth *)
  } cellmap (* apply to each cell, then collect the results in an array *)
} @:a2
(1 (2 3) (4 4 (5 2) 1)) a2 out

Тестовий випадок:

(1 (2 3) (4 4 (5 2) 1))    (* arg on TOS *)
{e d:e$wrap d 1-*}cellmap
out                        (* display TOS *)

Вихід без нових рядків:

(1 (2) (3) (4) (4) ((5)) ((2)) (1))

Це *як аргумент блоку коду?
Пуховик

@Downgoat в цьому випадку він завершує аргументи d-1разів. $funcце функція, якою можна керувати.
Conor O'Brien

2

PHP, 101 94 байт

врятував 1 байт завдяки @Christoph, врятував ще 6 натхненних цим.

function s($a){foreach($a as$b)if($b[0])foreach(s($b)as$c)$r[]=[$c];else$r[]=$b;return$r?:[];}

рекурсивна функція, досить прямо вперед

зламатися

function s($a)
{
    foreach($a as$b)                // loop through array
        if($b[0])                       // if element is array
            foreach(s($b)as$c)$r[]=[$c];    // append separated elements to result
        else$r[]=$b;                    // else append element to result
    return$r?:[];                   // return result, empty array for empty input
}

Де результат ініціалізується?
Ніл

@Neil: PHP не вимагає явної ініціалізації. Або $rотримує елементи в циклі, або функція повертає порожній масив. Він може отримувати повідомлення, але вони не надруковані з конфігурацією за замовчуванням.
Тит

Чи це не означає, що ви зможете телефонувати лише один раз?
Ніл

1
Ви можете також отримати з розуму: !cos(). cos()повертає nullдля кожного масиву і float! = 0 для кожного позитивного цілого числа. Я маю на увазі ... кого турбують попередження?
Крістоф

1
@Christoph: попередження друкуються, повідомлень немає (у налаштуваннях за замовчуванням). Але це чудова ідея! Увімкнено is_int: Повернення умови нічого не економить; Мені потрібен пробіл між elseі foreach. АЛЕ: $b[0]для цілого числа є NULL.
Тит

2

Python 2, 122 106 байт

Досить жахливий рахунок, просто відверта реалізація.

Дякуємо @Zachary T за допомогу зберегти 16 байт!

def x(l,a=[],d=0):
 n=lambda b:b and[n(b-1)]or l
 if'['in`l`:[x(e,a,d+1)for e in l];return a
 else:a+=n(d)

Зателефонуйте xз одним аргументом для запуску. Чомусь його можна запустити лише один раз.


Ви можете змінити a+=[n(l,d)]на a+=n(l,d),(зверніть увагу на
кінцеву

Вам навіть потрібно призначити t?
Zacharý

Чи спрацьовує це, коли ви називаєте це не раз?
Zacharý

Ви можете перейти nдо функції та видалити перший аргумент, оскільки це завжди буде l.
Zacharý


2

JavaScript (Firefox 30-57), 53 байти

f=a=>[for(e of a)for(d of e.map?f(e):[e])e.map?[d]:d]

Найкраща відповідь ES6, яку я маю поки що, - це 76 байт

f=(a,r=[],d=0)=>a.map(e=>e.map?f(e,r,d+1):r.push((n=d=>d?[n(d-1)]:e)(d)))&&r

2
В обох кодових блоках, я думаю, ви пропустили провідну f=.
Conor O'Brien

@ ConorO'Brien Ще раз ...
Ніл


1

Perl 6 , 60 47 байт

sub f{[$_~~List??|([$_] for .&f)!!$_ for |$^a]}

( Спробуйте в Інтернеті. )

Пояснення:

  1. [... for |$^a]: Ітерація над вхідним масивом та побудова з нього нового масиву.
  2. $_ ~~ List ?? ... !! ...: Для кожного елемента перевірте, чи це сам масив.
  3. |([$_] for .&f): Якщо елементом є масив, рекурсивно застосуйте до нього функцію, повторіть елементи нового масиву, повернутого з цього рекурсивного виклику, оберніть кожен елемент у свій власний масив та просуньте їх у зовнішній список.
  4. $_: Якщо елемент не є масивом, передайте його як-є.

1

Haskell, 71 байт

data L=N Int|C[L] 
d#C l=((C .pure.d)#)=<<l
d#n=[d n]
f(C l)=C$(id#)=<<l

Знову я маю визначити свій власний тип списку, оскільки списки уродженців Хаскелла не можуть бути довільно вкладені. Цей новий тип Lможна повернути з функції, але не буде надруковано за замовчуванням, тому для того, щоб побачити результат, я визначаю showекземпляр для L:

instance Show L where
  show (N n)=show n
  show (C l)=show l

Тепер ми можемо зробити кілька тестів у відповіді:

*Main> f $ C[N 1, C[N 2, N 3], C[N 4, N 4, C[N 5, N 2], N 1]]
[1,[2],[3],[4],[4],[[5]],[[2]],[1]]

*Main> f $ C[C[N 6, C[C[N 7]]]]
[[6],[[[7]]]]

Як це працює: проста рекурсія, яка проходить рівень гніздування як функція Cконструкторів. Ми починаємо з функції ідентичності, idі коли є список (-> відповідність шаблону d#C l=), ми додаємо ще один шар C(-> C .pure.d) до рекурсивного виклику #всіх елементів списку. Якщо ми зустрічаємо число, ми просто застосовуємо функцію рівня вкладення dдо числа.


0

APL (Діалог) , 44 байти *

Функція анонімного негласного префікса. Бере вкладений список APL як аргумент і повертає вкладений масив APL.

∊{⊃⊂⍣⍵,⍺}¨{⊃¨(j∊⎕D)⊆+\-'[]'∘.=j←⎕JSON⍵}

Спробуйте в Інтернеті!

{} Застосувати таку явну функцію, де аргумент представлений :

⎕JSON⍵ перетворити аргумент в JSON

j← зберігати в j

'[]'∘.= таблиці, де jдорівнює відкритий (верхній ряд) і закритий (нижній ряд) дужки

-⌿ верхній ряд мінус нижній ряд (зменшення вертикальної різниці)

+\ сукупна сума (це дає рівень гніздування для кожного персонажа)

()⊆ Розділ, починаючи новий розділ кожного разу, коли 1 не передує 1 в…

  j∊⎕D де кожен символ jє членом набору D запалюється

⊃¨ виберіть перший з кожного (це дає рівень вкладення на багатоцифрове число)

∊{...  застосовуються такі функції для кожного рівня вкладеності ( ), використовуючи відповідний елемент з ї nlisted (сплющені) аргументу як лівий аргумент ( ):

,⍺ ravel (listify) число (оскільки скалярів не можна закрити)

⊂⍣⍵ додавати рази

 розкрити (тому що найпотаємніший список - сам додаток)


* Використання Dyalog Classic з ⎕ML←3(за замовчуванням у багатьох системах), заміщення на та на . Тіо!

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