Поради щодо гольфу в Дж


33

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

Для тих , хто хоче дізнатися J, очевидне місце , щоб почати це jsoftware сайт і особливо словниковий запас , то навчання J керівництво і J для C програмістів керівництво.


1
У читанні GolfScript gets its own way far too often2019 року є щось смішне
Непов’язана струна

Відповіді:


14

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

  • Коли у вас поїзд їде, і вам потрібно застосувати функцію на іншому шляху ([:FLGR)і (LF@:GR)мати однакову кількість символів, але їх (LF@GR)зберігає. Якщо кадр G більше або дорівнює монадному рангу F, це правильне перетворення. Зокрема, усі поїзди мають нескінченний ранг, як , ,. ,: ~. /: \: [ ]і більшість застосувань #та |..

  • Якщо вам потрібно вибрати рядки зі списку, і ці рядки не мають пробілів, використовуйте >i{ab`cd`ef. Це брудно, але він зберігає символи для кожної нової рядки, з якою вам доведеться мати справу, якщо тільки ви не витягуєте одиночні символи, і навіть тоді список має бути довжиною 4, щоб бути коротшим. Те, що відбувається, полягає в тому, що невизначені імена трактуються як посилання на дієслова, а коли ви приймаєте заголовок цих дієслів, ви отримуєте рядок із іменем у вікні. Будь-які імена, які вже визначені як такі, що мають іменник типу, прислівник чи сполучник, не можуть бути використані таким чином, тому що ці імена раніше розв’язуються, `можливо, у них.

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

  • Сполучення на зразок (FGH)^:(u`v`w)можуть бути переписані u`v`w(FGH^:). Це працює для будь-якої довжини поїзда, навіть 1, хоча ви нічого не заощадите, лише якщо цей трюк видалить пароні з правильного аргументу. Цей трюк працює лише тоді, коли ви передзавантажите лівий операнд. (Поняття не маєте, що щойно сталося? Знайдіть «мовчазні прислівники» та вивчіть розділ « Розбір та виконання» Словника J.)

  • Не використовуйте a.&i., використовуйте u:! {&a.і 3&u:вони еквівалентні по довжині, проте, і перший може бути кориснішим у поєднанні (залежно від сполучення).

  • Такі речі, як (2%~F)і (F%2:)рівнозначні за довжиною. Це корисно, тому що іноді, залежно від того, як виглядає решта вашого поїзда, ви можете переструктурувати його @трюками, як написано в першому пункті, щоб зберегти деяких відчайдушних персонажів. (І звичайно, якщо Fє, ]а поїзд - монада, використовуючи %&2економить чару, да.)

  • Гакові поїзди з ]або [як найлівіший дієслово, напр (]FGH).

    • ]дозволяє розбити діадазовий додаток і використовувати лише правильний аргумент. (Поміняйте місцями на ліворуч (]FGH)~, штрафом не менше 1 символу, а може і більше.) Заощаджує чарівну (FGH)@], і дуже зручна в заробітках!
    • [у гачку, застосованій монадно, дозволяє зробити щось для побічних ефектів з правого боку, а потім повернути аргумент знову. Найбільш поширене використання - с1!:2 , можливо, із форматним бажанням.
  • I / O смокче. Прискоріть процес, зробивши петлі з усього, що можна. 1!:1наприклад, має ранг 0, і обидва 1!:2 3мають ранг _ 0, наприклад, використовуйте це, створюючи масиви 1 і бігайте 1!:1безпосередньо над ними. Зауважте, що ".також є ранг 1, тому зазвичай ви можете просто поставити це безпосередньо після1!:1 , а також не потрібно прикріплювати його через @чи ранжувати шнаніганів.

  • Нелегко знайти місця для цього, але це ::може бути корисно.

    • ::]^:_наприклад, це особливо потужна комбінація, яка дозволяє вам робити щось небезпечне, поки ви більше не зможете цього зробити. (З урахуванням звичних ^:_застережень -as-a-loop.)

    • Це також дозволяє використовувати {у списках, які не мають потрібного індексу, оскільки він видає помилку домену, коли це відбувається. Корисно, наприклад, взяти заголовок списку, тільки якщо він існує (спробуйте ::]повернути порожній список або ::_1:повернути код помилки тощо).

  • ]`($:@u)@.vЗазвичай це може бути коротшим, ніж u^:v^:_, особливо, за визначеннями uі з vякими можна обіграти. Аналогічний випадок має місце для умовно-типу u^:(1-v)VS. ]`u@.v. Розгляньте свої варіанти, особливо коли у вас багато плаває названих дієслів. Це також трохи гнучкіше, але пам’ятайте, що при використанні $:є глибина рекурсії, на яку легко натрапити. (Зазвичай щось на зразок 1800 ітерацій?)


Несприятлива хитрість справді класна.
FUZxxl

"збережіть деяких відчайдушних персонажів" Коли ви вивчаєте освітлення, все виглядає як переданий епітет! :)
Soham Chowdhury

1
"використання %&2економить чару, да." І -:рятує інше!
Лінн

11

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

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

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

Переклад імперативного коду є простим:

  1. нехай A - вхідний масив.
  2. чмi ← 0.
  3. якщо i ≥ len (A) повернути m .
  4. h ← max (0, h + A [ i ]).
  5. m ← макс ( м , год ).
  6. ii + 1.
  7. goto 3.

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

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

Тепер ці два кроки дуже легко здійснити в J. Ось переклад:

  1. (0 >. +)/\. y , 0- Цей крок діє з іншого кінця масиву, щоб краще відповідати парадигмі J. 0 >. +є мовчазним за 0 >. x + y.
  2. >./ y

У сукупності ми отримуємо дуже нескінченну реалізацію алгоритму:

>./ (0 >. +)/\. y , 0

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

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

  • Вивчіть словник. Він містить багато справді незрозумілих дієслів, які не мають сенсу, поки ви не побачите, наскільки вони корисні. Наприклад, монадика =спочатку дивна, але дуже корисна в мистецьких викликах ASCII.
  • Використовуйте діадік &у мовчазних контекстах, коли потрібно з'єднання влади. Лексика підказуєu@[&0 як мовчазну заміну мені 4 : 'u^:x yі так.
  • У багатьох випадках можна уникнути , [:або @:в послідовності , як u@v, вибираючи варіант з uякий має лівий аргумент. Наприклад, щоб відкинути перший елемент результату v, використовуйте 1}.vзамість, [:}.vякщо }.@vце неможливо з якихось причин.
  • ] vчасто коротше, ніж v@]якщо ви хочете використовувати монадик vу діадичному контексті. Це корисно, особливо колиv тривалий потяг дієслів.
  • Іноді можна писати m (n v w) yзамість (n v m&w) y. Це може уникнути пробілів і дужок.
  • #\замість >:@i.@#.
  • u &. vкорисна, коли vмає аверс. Коли ні, ви можете використовувати[: vinv u & v або u & (v :. vinv)замість цього.
  • Зрозумійте ранг і як ним користуватися. Постарайтеся возитися навколо сполучників рангів, поки не отримаєте щось, що підходить. Це допомагає зрозуміти, як ранг впливає на ваш код.
  • ^:_ є надзвичайно корисним для алгоритмів, де ви хочете досягти конвергенції, як, наприклад, заливка чи моделювання.
  • Знай свою стандартну бібліотеку. Він містить дуже корисні функції, що дозволяють заощадити тонни символів.
  • Копул =.і=: можуть бути вбудовані в будь-якій точці фрази. Використовуйте це, щоб зробити однолінійки, коли мовчазних позначень недостатньо.
  • Використовуйте монадик , замість декількох скорочень при зменшенні багатовимірних масивів.
  • Зрозумійте, які фрази підтримуються спеціальним кодом, коли виклик встановлює межі виконання. Деякі корисні речі функціонують в O ( n ) замість O ( n 2) ) протиінтуїтивно.
  • Ящики корисні для дерев.

Чи достатньо розумний J, щоб запустити ваше максимальне підрядне рішення в O (n) шляхом кешування повторно використаних обчислень, або він зробить пряму справу та запустить її в O (n ^ 2)?
Йона

@Jonah Я думаю, що це працює в квадратичний час.
FUZxxl

10

Обережно використовуйте петлі.

У той час як J має зациклення структури ( for. do. end., while. do. end.і варіації), якщо ви опиняєтеся їх допомогою є можливість того, що ваш алгоритм не грає в гольф сильних J і що є заощадження характеру , які будуть зроблені.

^:силова сполука - твій друг. Для виконання дієслівних xразів:

verb^:x

Якщо вам потрібен результат кожної ітерації у списку:

verb^:(i.x)

Ви також можете ^:умовно виконати дієслово:

  +:^:(3<])"0[ 1 2 3 4 5 6
1 2 3 8 10 12

Подвійне, +:якщо ^:предмет більший за 3 3<]( "0змінює ранг дієслова, щоб він працював над елементом за раз).


Значення в коробці діють як (i.x)приклад, тобто f^:(<x)еквівалентно f^:(i.x).
FireFly

9

Вхідні дані

1!:1[1 візьме один рядок вводу, який закінчується натисканням клавіші Enter.

1!:1[3 займе ряд рядків введення (закінчується Ctrl-D на моєму Mac, Ctrl-C в Windows).

Якщо ви намагаєтеся ввести числа, використовуючи ".оцінить рядок і поверне список номерів, готових до маніпулювання. Якщо ви приймаєте одне число, але вам потрібно діяти над цифрами окремо ".,.(завдяки коментарю Яна Дворака до цього) або "."0розділите рядок на окремі цифри:

   "."0[1!:1[1
12345
1 2 3 4 5

   ".,.1!:1[1
12345
1 2 3 4 5

Якщо ви читаєте в рядках, використовувати найкоротший спосіб отримання списку окремих рядків ;:. Це найкраще підходить для рядків, розділених пробілом:

   ;:1!:1[1
hello world
┌─────┬─────┐
│hello│world│
└─────┴─────┘

З цікавості, (я трохи погрався з J), що 1!:1[2вийде (якби)?
Гаффі

З того, що я можу зібрати на 1!:сторінці (я не знавець J) 2, це екран, тому введення з екрану не має особливого сенсу.
Гарет

Дякуємо за посилання Звідси це насправді виглядає як 2неправда? Я не маю на своєму комп'ютері J, щоб спробувати його на даний момент. Де я бачу 2, трохи нижче приміток про 1!:1, це для 1!:2.
Гаффі

@Gaffi Номери файлів для введення та виведення здаються послідовними, тому я здогадуюсь, що вони виправлені і що 2, 4 і 5 відображаються лише під час виведення, тому що не має сенсу намагатися вводити їх. Те саме відбувається і навпаки для 1 та 3.
Гарет

Оскільки ".це ранг 1-xx і ,.завжди створює 2D масив, ".,' ',.(зшивання з пробілом, розгортання та оцінка; 8 символів) можна замінити на справедливі ".,.(ravel items і оцінка; 4 символи).
Джон Дворак

6

Використання ітерації для обчислення послідовностей

Як правило, для вирішення завдання послідовності OEIS потрібно використовувати одну з формул, наведених на його сторінці. Деякі з них добре адаптуються до J, а інші - не дуже. Рекурсивні формули прямолінійні, проте ітерація може бути не простою. Я почав використовувати шаблон

(s(]f)^:[~]) n
          ]  Gets n
 s           The first value in the sequence
         ~   Commute the argument order, n is LHS and s is RHS
        [    Gets n
      ^:     Nest n times with an initial argument s
  (]f)         Compute f s
             Returns (f^n) s

де sперше значення в послідовності, f- це дієслово, яке обчислить наступний додаток з урахуванням попереднього терміна, і nє нульовим індексом терміна, який потрібно обчислити. Цей метод спирається на той факт, що при обчисленні сили діади LHS пов'язаний з діадою, щоб утворити нову монаду, і що монада вкладена в початкове значення. Діада, подана на прислівник потужності, - це гачок, де (]f)заданий індекс nна LHS та значення терміна в послідовності s. Крюк буде застосовуватися fна sяк монади, а потім ігнорувати , nщоб повернути результатf s .

Стандартна бібліотека

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

AND =: (17 b.) NB. it is actually '$:/ :(17 b.)'

Також доступні вбудовані дати та час.

Діапазони

Якщо у вас є набір значень [a, b, c]і ви хочете сформувати діапазон на основі їх продукту, як [0, 1, 2, ..., a*b*c-1], наприклад , типовим підходом було б знайти їх продукт, а потім сформувати діапазон, який може [:i.*/коштувати 6 байт. З того часу коротший шлях ,@i.на 4 байтиi. може формувати багатовимірні масиви, під час їх підрахунку, і вирівнювання створюватиме еквівалентний діапазон.

Друкується безперервно

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

База 10 цифр цілого числа

Стандартний спосіб отримання базових 10 цифр цілого числа - 10#.inv]це занадто велика вартість 8 байт! Альтернативою є перетворення його в рядок і розбір його в ранзі 0, "."0@":що зберігає байт, але ще кращий спосіб - ,.&.":це економія іншого байта, що робить остаточну вартість 6 байтів замість 8.


5

Подумайте використовувати явне визначення замість того, щоб писати мовчазне дієслово; Переконайтеся , що 3 :'і 'коштувати 5 байт, але ви можете заощадити багато @, @:і[: таким чином.


5

Деякі (досить) поширені хитрощі, які я бачив

Я ділюсь кількома корисними для мене речами. В основному все це поради, які я отримав сам, але більшість кредитів не маю.

Сума рангового масиву

Замість +/@:(FGH)використання (1#.FGH). Це означає дебазування до бази 1, що фактично означає підбиття масиву. Хоча він довший +/, він не потребує кришці або композиції, що часто робить його набагато коротшим, ніж використання +/.

Підрахунок слідуючих істин

Якщо у вас є логічний список, і ви хочете порахувати кількість простежуючих істин, використовуйте #.~. Дивіться тут . Відповідь APL дає хороше пояснення, як це працює. Зрозуміло, це мені було корисно лише двічі, але я зрозумів, що все одно поділюсь цим.

Під (&.)

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

Часто це корисно для та інших проблем із базовою конверсією, наприклад, цей код, який видаляє найбільш важливий біт з числа: }.&.#:(перетворити на список двійкових цифр, видалити першу цифру, а потім скасувати перетворення на список двійкових цифр та конвертувати назад до десяткової). Просте рішення є ще два байта: #.@}.@#:.

Підказка також корисна для викликів, коли вам потрібно працювати з десятковими цифрами, оскільки ви можете використовувати u&.":. Наприклад, короткий шлях миль дає колоти до десяткових цифр використання в: ,.&.":.

Останнім прикладом є знаходження величини вектора: +/&.:*:зауважте, що вам потрібно зібрати всі результати з *:-квадра з -для, &.:оскільки *:-квадра є нульовим рангом.


4

Коротші способи возитися з чинами

Іноді у вас буде такий код, як <"0 i.3 3ви хочете застосувати дієслово vза рангом r. Однак якщо ви використовуєте іменник (як 0), вам часто доведеться включати пробіл. Щоб уникнути цього, ви можете використовувати інше дієслово uеквівалентного рангу та використовувати u"vнатомість. Наприклад, оскільки +має ранг 0 0 0, ми можемо використовувати <"+замість<"0 .

Ось таблиця всіх дієслів та їх рангів (можна отримати за допомогою v b. 0):

0 0 0     > + * - % ^ | ! ? <. <: >. >: +. +: *. *: %: ^. j. o. q: r.
0 _ _     -. -: E. i: p:
1 0 1     p..
1 0 _     { A.
1 1 0     p.
1 1 1     #.
1 1 _     C.
1 _ _     ;: ". i. I.
2 _ 2     %.
_ 0 0     = < ~. ~: {: }: ?. L.
_ 1 0     #:
_ 1 _     $ # |. |: {. }. ": {::
_ _ _     , ; [ ] _: $. $: ,. ,: /: \: [: e. s: u: x: 0:

Щоб скористатися цією таблицею, знайдіть потрібний ранг rз лівої сторони, а потім виберіть відповідне дієслово vз правого боку. Наприклад, якщо мені потрібно векторизувати дієслово vна глибину 2 _ 2, то я знаходжу цей ранг зліва і вибираю %.справа. Тоді я використовую v"%.замість v"2 _ 2.


3

strings бібліотека: поради з гольфу

Бібліотека рядків надзвичайно корисна для того, щоб робити що-небудь за допомогою маніпуляцій зі струнами. Звичайно, це займає include'strings'(що дуже дорого, враховуючи J), але ви можете часом отримати користь.

stringreplace

Знайти себе за допомогою заміни рядків? Зауважте, що A stringreplace Bте саме, щоB rplc A .

Насправді це rplcреалізується так:

   rplc
 stringreplace~

cuts

Дієслово cutsзабезпечує таким чином:

вирізати y на x (сполучення)
рядок (дієслова скорочує n) текст
  n = _1 до, але не включаючи рядок
  n = 1 до рядка включно
  n = _2 після, але не включає рядок
  n = 2 після і включаючи рядок

Так що це дійсно нарізка струни.


3

Отримання чисел від 0 до 4

Якщо у вашому коді є обмеження на використання чисел:

0 %_ : один, поділений на нескінченність.
1 #_ : скільки нескінченностей?
2 #_ _ : дві нескінченності.
3 verb : є вбудований.
4 dyad : ще одна вбудована.

Отримання чисел від 10 до 35

База-inifinity литералов: 11 : _bb, 26 : і _bqт.д.


3

Мовчазне програмування

Основи

Дієдичне дієслово

x (F G H) y == (x F y) G (x H y)
x (F G) y == x F (G y)
x ([: G H) y == G (x H y)  NB. G is called monadically

NB. Verbs are grouped from the right by units of 3.
NB. For the following, think like G, I, K are replaced by the results of (x G y) etc.
NB. and then the sentence is run as usual.
x (F G H I J K) y == x (F (G H (I J K))) y
                  == x F ((x G y) H ((x I y) J (x K y)))

NB. Using conjunctions for dyadic verb
x F@G y == F (x G y)  NB. Atop; Same as x ([: F G) y; Consider as golfing alternatives
x F&G y == (G x) F (G y)  NB. Compose; G is applied monadically to both arguments

Монадійське дієслово

(F G H) y == (F y) G (H y)
(G H) y == y G (H y)  NB. Note that this is different from APL
([: G H) y == G (H y)
(F G H I J K) y == (F (G H (I J K))) y
                == y F ((G y) H ((I y) J (K y)))
F@G y == F (G y)

Різне

x&F y == x F y
F&y x == x F y
y F~ x == x F y
F~ y == y F y

Витівки

(F x) G (H y)

Неявні рішення: (G~F)~H; залежно від власне дієслів, подумайте про перестановку лівого та правого аргументів для видалення ~.

x ((G~F)~H) y
x (G~F)~ (H y)
(H y) (G~F) x
(H y) G~ (F x)
(F x) G (H y)

Монадико-діадичні заміни

>:y == 1+y
<:y == 1-~y or _1+y
+:y == 2*y
-.y == 1-y
-:y == 2%~y
*:y == 2^~y
#.y == 2#.y
#.inv y == 2#.inv y  NB. #: doesn't work this way
{.y == 0{y
{:y == _1{y
}.y == 1}.y
+/y == 1#.y

1
(G~F)~Hце чисте міхурне добро!
Іона

2

& твій друг, використовуй це розумно

vє дієсловом, nє іменником xіy є лівими та правими аргументами відповідно.

Монада &: Представляємо~ всередині ланцюга прислівник / сполучник

Прислівник / ланцюжок сполучників оцінюється зліва. Тож щось на кшталт _2&+/\&.>не буде працювати, оскільки воно розбирає, як (_2&+)/\&.>ми хочемо _2&(+/\)&.>. У цьому випадку, заміна лівою / правою частиною +/\може зберегти байт, як у +/\~&_2&.>тому, що цей розбирає як ((+/\)~)&_2&.>. Щоб дізнатися, чому це працює:

+/\~&_2 y
is equivalent to
y +/\~ _2
is equivalent to
_2 +/\ y
is equivalent to
_2&(+/\) y

Діад &: Повторітьx рази

Чи знаєте ви , що якщо ви даєте лівий аргумент xдо &, функція застосовує йогоx разy ? Досить багато проблем вимагають зробити певний час роботи x. Це в основному досягається двома способами:

  • Використовуйте оператор живлення ^:без правого операнду

Якщо операція є v, то v^:стає прислівниковим потягом, який, отримуючи лівий операнд, стає монадичним дієсловом. Так vзастосовується до y, xразів.

x(v^:)y
is equivalent to
(v^:x)y
  • Використовуйте діадік & як найвіддаленіший сполучник

Щоб скористатись цим, вам потрібно визначити постійне nта діадичне дієслово u, так що n u yабо y u nє рівнозначним v. Тоді можна писатиn&u абоu&n розв’язати всю задачу. Ця форма є найбільш ефективною, коли вибір константи очевидний, наприклад, 3 in 3 u:(перетворити символи на ASCII значення).

Крім того, u&nтрохи кращим є те, n&uколи зовнішня структура uє сполучником чи прислівником (у такому випадку n&uмає бути n&(u); ви можете зробитиu~&n замість).

Зауважте, що ви можете розмістити діадик в &будь-якому місці поїзда, щоб досягти повторення довільної функції до довільного аргументу, в аналогічному сенсі до динамічного ^:.

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