Советы по игре в гольф в J


33

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

Для тех , кто хочет узнать J, очевидное место , чтобы начать это jsoftware сайт и особенно словарный запас , то обучение J руководство и J для C программистов руководство.


1
Что-то смешное в чтении GolfScript gets its own way far too oftenв 2019 году.
Несвязанная строка

Ответы:


14

Есть несколько тонкостей, чтобы выжать последние несколько символов в J. Для следующего предположим, что каждая заглавная буква является примитивным глаголом (то есть я удаляю пробелы, которые в противном случае потребовались бы для разделения имен).

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

  • Если вам нужно выбрать строки из списка, и у этих строк нет пробелов, используйте >i{ab`cd`ef. Это грязно, но сохраняет символы для каждой новой строки, с которой вам приходится иметь дело, если только вы не вытягиваете отдельные символы, и даже в этом случае charlist должен быть длиной 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, и не нужно прикреплять его через @или ранг махинаций.

  • Это не легко найти места, чтобы поставить это, но ::может быть полезно.

    • ::]^:_например, это особенно мощная комбинация, которая позволяет вам делать что-то опасное, пока вы больше не можете это делать. (С учетом обычных ^:_предостережений типа «как петля».)

    • Это также позволяет вам использовать {списки, которые не имеют желаемого индекса, потому что при этом возникает ошибка домена. Например, полезно взять заголовок списка только в том случае, если он существует (попробуйте использовать, ::]чтобы вернуть пустой список или ::_1:вернуть код ошибки и т. Д.).

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


Плохой трюк действительно крутой.
FUZxxl

«Спасите некоторых отчаянных персонажей» Когда вы учитесь освещены, все выглядит как переданный эпитет! :)
Сохам Чоудхури

1
"использование %&2спасает полукокса" И -:спасает другого!
Линн

11

Самое важное при игре в гольф в J - это не только понять проблему, но и свести проблему к серии преобразований массива. Вы должны понимать этот способ мышления, чтобы иметь успех с J-кодом.

Например, недавняя задача попросила решить самую большую проблему подмассива . Стандартный алгоритм для решения этой проблемы - это алгоритм Кадане, имеющий следующее неофициальное описание:

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

Перевод в императивный код прост:

  1. пусть A будет входным массивом.
  2. hmi ← 0.
  3. если i ≥ len (A), вернуть m .
  4. h ← max (0, h + A [ i ]).
  5. m ← max ( м , ч ).
  6. яя + 1.
  7. перейти к 3.

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

  1. Просканируйте массив, чтобы вычислить длины самых больших подмассивов, оканчивающихся на каждый индекс.
  2. Уменьшите эти длины с помощью функции max, чтобы найти максимум.

Теперь эти два шага очень легко реализовать в J. Вот перевод:

  1. (0 >. +)/\. y , 0- Этот шаг работает с другого конца массива, чтобы лучше соответствовать парадигме J. 0 >. +молчит для 0 >. x + y.
  2. >./ y

Вместе мы получаем очень краткую реализацию алгоритма:

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

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

Вот некоторые уловки, которые я накопил со временем. Этот список будет расширяться по мере того, как я получу больше знаний в области гольфа.

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

Достаточно ли уместен J, чтобы запустить решение max subarray в O (n), кэшируя повторно используемые вычисления, или он сделает простую вещь и запустит его в O (n ^ 2)?
Иона

@ Джона, я думаю, это работает в квадратичном времени.
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 займет одну строку ввода, завершенную нажатием клавиши ввода.

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 и ,.всегда создает двумерный массив, ".,' ',.(стежок с пробелом, разбить и оценить; 8 символов) можно заменить на просто ".,.(разбить элементы и оценить; 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 ответ дает хорошее объяснение того , как это работает. Конечно, это было полезно только для меня дважды, но я решил, что поделюсь этим в любом случае.

Под (&.)

Не конкретный трюк, а просто общее предположение: наречие &.часто приводит к изящным и (что более важно) кратким решениям. Имейте это в виду, когда вы играете в гольф.

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

Under также полезен для задач, где вам нужно работать с десятичными цифрами, так как вы можете использовать u&.":. Например, короткий путь миль дает колоть до десятичных цифр использования в: ,.&.":.

Последний пример - определение величины вектора: +/&.:*:обратите внимание, что вам нужно собрать все результаты из *:-square с -under, &.:так как *:-square имеет нулевой ранг.


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обеспечивает таким образом:

разрезать у в х (соединение)
строка (глагол режет 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левый и правый аргументы, соответственно.

Monad &: ввести ~внутри цепочки наречий / соединения

Цепочка наречий / соединения оценивается слева. Так что что-то вроде _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 в 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.