Варення не додавати так


16

Фон

Арифметичні атоми Желе векторнізуються автоматично. Насправді, x + y добре визначається, коли x і y є числами або нерівними масивами чисел. Вихідний код Jelly реалізує цю поведінку за допомогою загального векторизатора, але для цього завдання ми розглянемо лише додавання цілих чисел та вкладених цілих масивів.

Визначення

Визначте глибину x як 0, якщо x - ціле число, як 1, якщо це (можливо, порожній) плоский масив цілих чисел, і як n + 1, якщо він містить хоча б один елемент глибини n і відсутні елементи глибини k> н .

Таким чином, 1 має глибину 0 , [] і [1] і [1, 1] мають глибину 1 , [[], []] і [[1], [1]] і [[1]] і [1 , []] мають глибину 2 , [1, [1, [1]]] мають глибину 3 і т.д.

Операція x + y визначається наступним чином.

  1. Якщо x і y мають глибину 0 , поверніть їх суму.

  2. Якщо x і y мають рівні, але позитивні глибини, рекурсивно застосовуйте + до всіх елементів x та відповідних елементів y .

    Якщо х і у мають різну довжину, додайте хвіст довшого масиву до масиву сум.

    Поверніть результат.

  3. Якщо глибина x суворо менша за глибину y , рекурсивно застосуйте + до x та всіх елементів y та поверніть результат.

    Зробіть навпаки, якщо глибина y суворо менша, ніж х .

Наприклад, розглянемо операцію [1, [2, 3], [4]] + [[[10, 20], [30], 40, 50], 60] .

  • Глибина лівого аргументу дорівнює 2 , тоді як глибина правого аргументу - 3 , тому ми обчислюємо [1, [2, 3], [4]] + [[10, 20], [30], 40, 50 ] та [1, [2, 3], [4]] + 60 .

    • [1, [2, 3], [4]] і [[10, 20], [30], 40, 50] мають глибину 2 , тому обчислюємо 1 + [10, 20] , [2, 3] + [30] і [4] + 40 .

      • 1 + [10, 20] = [1 + 10, 1 + 20] = [11, 21]

      • [2, 3] + [30] = [2 + 30, 3] = [32, 3]

        Зауважте, що 3 залишається недоторканим, оскільки він не має відповідного елемента.

      • [4] + 40 = [4 + 40] = [44]


      50 не має відповідний елемент, так що результат [[[11, 21], [32, 3], [44], 50]] .

    • [1, [2, 3], [4]] + 60 = [1 + 60, [2, 3] + 60, [4] + 60] = [61, [2 + 60, 3 + 60], [ 4 + 60]] , в результаті чого [61, [62, 63], [64]] .

  • Кінцевий результат - [[[11, 21], [32, 3], [44], 50], [61, [62, 63], [64]]] .

Завдання

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

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

Щоб запобігти нудним і неперевершеним рішенням, якщо мова має цю точну операцію як вбудовану, ви можете не використовувати цю мову.

Дозволено використовувати всі вбудовані мови всіх інших мов. Якщо ваша обрана мова дозволяє це, ви можете перевантажувати та / або переосмислювати вбудований додаток.

Це , тому виграє найкоротший код у байтах.

Тестові справи

0 + 0                           = 0
[-1, 0, -1] + [1]               = [0, 0, -1]
[] + [0]                        = [0]
[] + 0                          = []
[] + []                         = []
[[], 0] + []                    = [[], []]
[1, 2, 3] + 10                  = [11, 12, 13]
[1, 2, 3] + [10]                = [11, 2, 3]
[1, 2, 3] + [10, [20]]          = [[11, 12, 13], [21, 2, 3]]
[1, 2, 3, []] + [10, [20]]      = [11, [22], 3, []]
[1, [2, [3, [4]]]] + [10, [20]] = [[11, [21]], [[12, [22]], [13, [24]]]]

Щоб створити більше тестових випадків, ви можете використовувати цю програму Jelly .


Що робити, якщо наша мова не підтримує рвані масиви? Чи дозволяється нам реструктурувати вхідні дані чи ми повинні реалізувати нерівні масиви? А може просто використовувати іншу мову?
милі

Що ви маєте на увазі під реструктуризацією вхідних даних ?
Денніс

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

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

3
Гей, приємний заголовок! .. Тепер, коли Google допоміг мені отримати його :-)
Луїс Мендо

Відповіді:


3

Pyth, 42 байти

L?sIb0heSyM+b0M?qFyMJ,GH?yGgM.tJ0+GHgLFyDJ

Тестовий набір

Останні 4 байти просто запускають функцію на вході.

L?sIb0heSyM+b0M?qFyMJ,GH?yGgM.tJ0+GHgLFyDJ

L?sIb0heSyM+b0
                  Define y(b), a helper function to calculate the depth.
 ?                Ternary:
  sIb             If b is invariant under the s function, which is only the case
                  if s is an int.
     0            The depth is 0.
           +b0    Add a 0 on to b. This handles the edge case where b is [].
         yM       Map each to their depth
       eS         Take the max.
      h           Add one.

M?qFyMJ,GH?yGgM.tJ0+GHgLFyDJ
M                               Define g(G, H), which calculates the Jelly +.
 ?                              Ternary:
       ,GH                      Form [G, H].
      J                         Save it to J.
    yM                          Map each to its depth.
  qF                            Check if they are equal.
          ?yG                   If so, check if the depth is nonzero.
               .tJ0             If so, transpose J, pairing each element of each
                                argument with the corresponding element of the
                                other. Pad with zeroes.
             gM                 Map each to its Jelly +.
                   +GH          If the depths are zero, return the normal sum.
                         yDJ    If the depths are different, order J by depth.
                      gLF       Apply the function which left-maps the Jelly +
                                function to the two values. The first is
                                treated as a constant, while the second varies
                                over elements over the second values.

7

APL, 44 байти

{1=≡⍺⍵:⍺+⍵⋄=/∆←|≡¨⍺⍵:⊃∇¨/↓↑⍺⍵⋄</∆:⍺∘∇¨⍵⋄⍵∇⍺}

APL також +розповсюджує масиви, але досить іншим способом, щоб це реально не можна було використовувати. Однак є вбудована функція глибини ( ).

Пояснення:

  • 1=≡⍺⍵:⍺+⍵: якщо глибини дорівнює нулю (і, отже, глибина ⍺ ⍵дорівнює 1), додайте їх.
  • ∆←|≡¨⍺⍵: Взяти абсолютні глибини як і і зберігати їх в . ( дає негативне значення, якщо не всі елементи мають однакову глибину.)
  • =/∆: якщо вони мають однакову глибину:
    • ↓↑⍺⍵: прокладіть найкоротший масив з нулями, щоб відповідати довшому масиву
    • ⊃∇¨/: розподілити функцію по обох масивах
  • </∆: якщо глибина менше, ніж :
    • ⍺∘∇¨⍵: прив’яжіть, а потім перетасуйте
  • ⍵∇⍺: якщо нічого іншого (так глибше ), поміняйте аргументи та повторіть спробу.

3
Іноді я думаю, що я добре знаю APL. Тоді я бачу такий шедевр і розумію, що ледве його зовсім не знаю.
Алекс А.

Чи дійсно символи APL вважаються байтами?
металлім

@metalim APL має застарілі кодові сторінки, що передували Unicode протягом декількох десятиліть. У них кожен символ - це один байт.
Денніс

Тоді тип кодування повинен бути забезпечений розчином. Просто ІМО.
металлім

@metalim Я додав посилання.
Адам

5

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

d=Depth
x_~f~y_/;d@x>d@y:=y~f~x
x_~f~y_/;d@x<d@y:=x~f~#&/@y
x_List~f~y_:=MapThread[f,{x,y}~PadRight~Automatic]
x_~f~y_=x+y

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

x_~f~y_/;d@x>d@y:=y~f~x

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

x_~f~y_/;d@x<d@y:=x~f~#&/@y

Якщо глибина xменше Thann , що з y, замінити кожне значення #в yс f[x,#], який піклується про розподіл для аргументів нерівній глибини.

x_List~f~y_:=MapThread[f,{x,y}~PadRight~Automatic]

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

І нарешті, базовий випадок:

x_~f~y_=x+y

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


5

Haskell, 150 байт

data L=S Int|V{v::[L]}
d(V z)=1+maximum(d<$>S 0:z);d _=0
S x!S y=S$x+y
x!y|d x<d y=V$(x!)<$>v y|d x>d y=y!x|1<2=V$v x#v y
(x:a)#(y:b)=x!y:a#b;a#b=a++b

Пояснення

Перший рядок визначає алгебраїчний тип даних L, який є або Sкаларом (містить an Int), або Vектором (містить список Ls, доступ до якого здійснюється за допомогою програми для отримання запису v, що є частковою функцією L → [L].)

Другий рядок визначає функцію глибини : глибина Vектора дорівнює плюс його максимальна глибина. Я передую S 0значенням у векторі, так що depth [] == 1 + maximum [depth (S 0)] == 1. Глибина "будь-чого іншого" (скаляр) є 0.

Третій рядок визначає базовий випадок для !(функція додавання): сума скалярів - просто скаляр.

П'ятий рядок визначає варіант, zipWith (!)який просто вибирає елементи з найдовшого списку, коли один із них порожній.

Четвертий рядок розділений на три випадки:

x!y | d x<d y = V$(x!)<$>v y
    | d x>d y = y!x
    | True    = V$v x#v y
  • Якщо глибина xсуворо менша за глибину y, намалюйте (x!)елементи елементів y. (Використання vгарантовано є дійсним, як d(y) ≥ 1.)

  • Якщо глибина xсуворо більша, переверніть аргументи та перезапустіть.

  • Якщо їх глибина однакова, зафіксуйте аргументи разом з (!). (Використання vгарантовано є дійсним, оскільки справа d(x) = d(y) = 0розглядалася як базовий випадок.)

Тестові справи

instance Show L where
  show (S x) = show x
  show (V x) = show x

lArg = V [S 1, V [S 2, V [S 3, V [S 4]]]]
rArg = V [S 10, V [S 20]]

Потім show (lArg ! rArg) == "[[11,[21]],[[12,[22]],[13,[24]]]]".


Я теж це виправив ^^ (я поміняв рядки для читабельності, але я зробив це неправильно ...) Це importтому, що Ideone має старий компілятор Haskell. Сучасні версії GHC помістити <$>в Prelude, так що вам не потрібно імпортувати , Control.Applicativeщоб використовувати його в ці дні.
Лінн

Agh занадто багато редагувань одночасно з іншими моїми діями: P І, звичайно, зараз це здається нормальним, але я вважаю це досить дивно, що викликає помилку компіляції. Чи повинні всі біти функції, що відповідають функції, повинні бути послідовними?
FryAmTheEggman

Це точно так.
Лінн

Добре, дякую за всю вашу допомогу :) "Я колись заграю цю мову" - FryAmTheEggman 7 років тому.
FryAmTheEggman

4

Java, 802 794 754 746 байт

Я вирішив взятися за @ Dennis ♦ за виклик оперувати на струнах "в крайньому випадку", тому що це було, мабуть, "занадто складно". Крім того, найгіршою мовою для гольфу на.

Масиви на вході розділені комами, оточені квадратними дужками та без пробілу.

Повна програма з функціями, загорнутою в клас та з тестовими кейсами

import java.util.*;
List<String>p(String s){List r=new ArrayList<String>();String p="";int l=0;for(char c:s.substring(1,s.length()-1).toCharArray()){l+=c=='['?1:c==']'?-1:0;if(c==','&&l<1){r.add(p);p="";}else p+=c;}if(p!="")r.add(p);return r;}
int d(String s){int l=0;if(s.contains("[")){for(String c:p(s))l=d(c)>l?d(c):l;l++;}return l;}
String f(String x,String y){int i=0;String r="";if(d(x)<1&&d(y)<1)r+=Integer.valueOf(x)+Integer.valueOf(y);else{r="[";if(d(x)<d(y))for(String k:p(y))r+=(i++<1?"":",")+f(x,k);else if(d(x)>d(y))for(String k:p(x))r+=(i++<1?"":",")+f(k,y);else for(;i<p(x).size()||i<p(y).size();i++)r+=(i<1?"":",")+(i<p(x).size()&&i<p(y).size()?f(p(x).get(i),p(y).get(i)):i<p(x).size()?p(x).get(i):p(y).get(i));r+="]";}return r;}

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

-31 байт від @ user902383, пропонуючи використовувати foreach над перетвореним масивом символів, і тоді я врятував трохи більше від перестановки блоків if у заключній частині.


Це вражає.
Денніс

Я думаю, що якщо ви заміните свої петлі на масив циклу foreach через масив char, отриманий з рядка, ви могли б зберегти досить багато байтів.
user902383

1
Errr ... Java підтримує нерівні масиви; Я не впевнений, що ти маєш на увазі під цим. Використання Object[], яке містить або вкладені, Object[]або Integer. Або просто негенеричний список.
Роберт Фрейзер

4

Python 2.7, 261 209 202 198 191 185 197 181 байт

Тривіальне рішення FGITW

EDIT: Звичайно @Dennis це б'є

Дякуємо @LeakyNun за збереження 57 байт із порадами щодо лямбда-виразів та 2 байти з непотрібних дужок.

Завдяки @Adnan за 4 байти через пропозицію використовувати typeзамістьisinstance

Завдяки @Lynn за 7 байт із -~таmap

Завдяки @FryAmTheEggman за, z>=[]а неtype

+12 байт для перетворення лямбда в інше та виправлення основної помилки

-16 байт завдяки @Kevin Lau - не Кенні

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

d=lambda z:z==[]or z>[]and-~max(map(d,z))
p=lambda x,y:p(y,x)if d(x)>d(y)else(x+y if d(x)<1 else[p(a,b)for a,b in zip(x,y)]+x[len(y):]+y[len(x):])if d(x)==d(y)else[p(a,x)for a in y]

Ще коротше перейти на Python 2.7 та написатиz==[]or`z`>']'and ...
Lynn

Крім того, я думаю, що заміна max(d(a)+1for a in z)на -~max(d(a)for a in z)економить байт (тому що ви можете видалити пробіл раніше max). Який тоді просто -~max(map(d,z)).
Лінн

Перемикання на Python 2 зберігає ще в тому , що ви можете змінити [p(a,b)for a,b in zip(x,y)]в map(p,x,y). Ви все ще можете зробити це за 3, але вам потрібно додати дзвінок у list. Я думаю, ви також могли б покращити пропозицію Лінни бути z>=[]. Не пов'язані між собою, ви також можете мати можливість заміняти порядок typeпорівняння для економії місця.
FryAmTheEggman

Помилка, я мав на увазі or`z`>'[', звичайно, але я не можу більше змінити свій коментар. Але дійсно, z>[]ще коротше ( ==справа вже розглядається)!
Лінн

@FryAmTheEggman карта не працює, коли списки мають різні розміри; коректно зафіксована блискавка. Я оновлюсь зі списком перевірки тхо
Блакитний

3

Python 2, 145 136 байт

d=lambda t:t>{}and-~max(map(d,t+[0]))
s=lambda x,y:s(y,x)if d(y)<d(x)else map(s,(x,[x]*len(y))[d(x)<d(y)],y)if d(y)else(x or 0)+(y or 0)

Перевірте це на Ideone .

Як це працює

У Python 2 всі цілі числа менше, ніж усі словники, але всі списки є більшими. d рекурсивно обчислює глибину t , повертаючи 0 для цілих чисел або збільшеного максимуму глибин його елементів і 0 . t+[0]уникає спеціального кодування порожнього списку.

s рекурсивно обчислює суму желе з х і у .

Якщо глибина y перевищує x 's, s(y,x)викликає s заміненими аргументами, переконуючись, що d (x) ≤ d (y) .

Якщо y має позитивну глибину, map(s,(x,[x]*len(y))[d(x)<d(y)],y)робимо наступне.

  • Якщо глибина xy ' збігається, вона виконується map(s,x,y), відображаючи s над усіма елементами x та відповідними елементами y .

    У випадку зі списками різної довжини, карта передасть None як лівий або правий аргумент для відсутніх елементів у коротшому списку.

  • Якщо глибина x нижча, ніж у y , вона виконується map(s,[x]*len(y),y), відображаючи s (x, ·) над y .

Якщо y (і, отже, x ) має глибину 0 , (x or 0)+(y or 0)замінює хибні аргументи ( None або 0 ) нулями і повертає суму отриманих цілих чисел.


1

JavaScript (ES6), 152 байти

f=(a,b,g=a=>a.map?1+Math.max(0,...a.map(g)):0)=>g(a)<g(b)?f(b,a):g(b)<g(a)?a.map(e=>f(e,b)):g(a)?a.length<b.length?f(b,a):a.map((e,i)=>f(e,b[i]||0)):a+b
;t=(x,y,z)=>o.textContent+=`
${JSON.stringify(x)}
${JSON.stringify(y)}
${JSON.stringify(z)}
${JSON.stringify(f(x,y))}
`;`
0 + 0                           = 0
[-1, 0, -1] + [1]               = [0, 0, -1]
[] + [0]                        = [0]
[] + 0                          = []
[] + []                         = []
[[], 0] + []                    = [[], []]
[1, 2, 3] + 10                  = [11, 12, 13]
[1, 2, 3] + [10]                = [11, 2, 3]
[1, 2, 3] + [10, [20]]          = [[11, 12, 13], [21, 2, 3]]
[1, 2, 3, []] + [10, [20]]      = [11, [22], 3, []]
[1, [2, [3, [4]]]] + [10, [20]] = [[11, [21]], [[12, [22]], [13, [24]]]]`.slice(1).split`
`.map(l=>t(...l.split(/ [+=] /).map(a=>JSON.parse(a))));
<pre id=o></pre>


1

Рубін 2,3, 143 145 148 149 байт

У Рубі є всі ці маленькі химерності в тому, як zipпрацює з масивами різної довжини та mapз функціями з багато аргументів, що робить це дуже цікавим для гри в гольф.

f=->x,y{d=->a{-~(a.map(&d).max||0)rescue 0}
d[x]<d[y]?y.map{|e|f[x,e]}:d[x]>d[y]?x.map{|e|f[e,y]}:d[x]<1?x+(y||0):[*x.zip(y).map(&f),*y[x.size..-1]]}

Це дуже цікаво - я ніколи не бачив цієї помилки для цієї функції. Я все-таки виправляв деякі речі через інші помилки зараз, але окрім того, що це працює для мене (але все ще не вдається на ideone). Я думаю, це тому, що ideone працює 2.1, а у мене 2.3, тож, можливо, 2.1 просто не можеmap функцію з двома аргументами, як я її встановив наприкінці. Ось версія відредагована для 2.1, яка працює, яка налаштовує mapвиклик наприкінці на роботу. ideone.com/q1jqTA
Значення чорнила

1

Джулія, 113 байт

~=endof;!t=0t!=0&&1+maximum(!,[t;0])
x::Array+y::Array=(!x,~x)>(!y,~y)?y+x:!x<!y?map(t->x+t,y):~x<~y?[x;0]+y:x.+y

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

Як це працює

~=endof

створює 1-байтовий псевдонім для endof , який повертає довжину масиву.

!t=0t!=0&&1+maximum(!,[t;0])

визначає функцію глибини. Глибина t дорівнює нулю, якщо і лише тоді, коли 0t == 0 . Якщо ні, то t - це масив, і його глибина обчислюється як збільшений максимум глибин його елементів і 0 . [t;0]додає а 0 до масиву t , що дозволяє уникнути необхідності в спеціальному випадку-порожній масив.

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

Ми переосмислюємо + для пари масивів через

x::Array+y::Array=(!x,~x)>(!y,~y)?y+x:!x<!y?map(t->x+t,y):~x<~y?[x;0]+y:x.+y

Це не впливає на визначення + для аргументів integer / integer, array / integer або integer / array.

(!x,~x)>(!y,~y)лексикографічно порівнює пари глибин і довжин як x, так і y . Якщо глибина x перевищує y ', або якщо їх глибина відповідає і довжина x перевищує y ',y+x рекурсивно викликає + із заміненими аргументами.

В іншому випадку тестуйте, !x<!yчи глибина x нижча, ніж у y . Якщо це так, map(t->x+t,y)карти x + · над y .

Якщо глибина збігається, ~x<~yтестуйте, якщо x коротше y . Якщо це так, [x;0]+yрекурсивно дзвонить + після додавання 0 до лівого аргументу.

Нарешті, якщо обидві глибини та довжини однакові, x.+yкарти + над усіма елементами x та відповідними елементами y .

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