Какие общие советы у вас есть для игры в гольф в Юлии? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, которые, по крайней мере, несколько специфичны для Джулии (например, «удалить комментарии» - это не ответ).
ПРИМЕЧАНИЕ: ниже могут содержаться некоторые устаревшие советы, так как Юлия еще не совсем стабилизировалась с точки зрения структуры.
Несколько трюков, чтобы сохранить несколько персонажей
Операторы перегрузки с часто используемыми двоичными функциями . Например, если вам нужно сделать много целочисленных делений и нет необходимости в обратном делении, используйте \ =div, и тогда вы сможете печатать a\bвместо div(a,b). Обратите внимание на пробел - это необходимо, чтобы избежать его синтаксического анализа как оператора "\ =". Также обратите внимание, что, если перегружено на уровне подсказки REPL, используйте (\)=Base.(\)или \ =Base. \для его сброса. ПРИМЕЧАНИЕ: некоторые функции имеют предопределенные существующие операторы UTF-8, например, ÷для div, как отметил Алекс А.
Используйте ^ со строками для условного вывода . То есть вместо того a>0?"Hi":"", "Hi"^(a>0)чтобы использовать для сохранения одного байта, или для логического a, используйте "Hi"^aдля сохранения трех байтов.
(иногда) Храните маленькие векторы фиксированного размера как отдельные переменные . Например, вместо a=split("Hi there"," "), вы можете избежать a[1]и a[2]использовать a,b=split("Hi there"," "), на который можно ссылаться как aи b, сохраняя три байта для каждого использования, за счет всего двух дополнительных символов при назначении. Очевидно, не делайте этого, если вы можете работать с векторными операциями.
Получите доступ к первому элементу Array с помощью[] - для массивов, выражение A[]эквивалентно A[1]. Обратите внимание, что это не работает для строк, если вы хотите получить первый символ, или для кортежей.
Не используйте isempty для массивов, кортежей или строк - вместо этого используйте ==[]для массивов и ==()кортежей; аналогично для негатива используйте !=[]и !=(). Для строк, используйте ==""для пустого, но используйте >""для не пустого, так как "" лексикографически перед любой другой строкой.
Используйте правильный логический оператор короткого замыкания вместо «если» . Это может быть немного менее специфично для Юлии, но это стоит иметь в виду. x<=1&&"Hi"можно записать как x>1||"Hi"сохранение символа (если возвращение логического значения не имеет значения).
Не используйте содержащийся для проверки наличия символа в строке - если вы ограничены базовым ASCII, используйте in('^',s)вместо contains(s,"^"). Если вы можете использовать другие символы, вы можете сэкономить немного больше '^'∈s, но учтите, что ∈в UTF-8 это 3 байта.
Ищете минимальные / максимальные значения в массиве? Не используйте минимум или максимум - вместо того, чтобы использовать minimum(x)или maximum(x), используйте min(x...)или max(x...), чтобы убрать один символ из вашего кода, если вы знаете, xбудет иметь по крайней мере два элемента. В качестве альтернативы, если вы знаете, что все элементы xбудут неотрицательными, используйте minabs(x)илиmaxabs(x)
Там, где это возможно и разрешено заданием, используйте вместо \ n фактический символ новой строки - обратите внимание, что это сделает ваш код труднее для чтения, и это может означать, что вам нужно предоставить версию «без заглядывания», чтобы люди могли на самом деле понять Это.
Поставьте опции после строки регулярного выражения - если вы хотите иметь строку регулярного выражения в многострочном режиме, например, не печатайте r"(?m)match^ this", печатайте r"match^ this"m, сохраняя три символа.
Обратные одномерные массивы с использованием flipud - reverse(x)на один байт длиннее flipud(x)и будут выполнять ту же операцию, поэтому последний лучше.
Где возможно, используйте конкатенацию массива вместо push !, unshift !, append !, или prepend! - для обычных массивов это можно сделать легко. Для массивов типа Any с элементами массива вам понадобятся фигурные скобки вокруг добавленных массивов (то есть {[1,2]}, нет {1,2}) - для Julia 0.4 вам понадобится Any[[1,2]].
Используйте индексирование массива, чтобы получить размер массива или строки - когда вы используете endиндексирование массива, оно автоматически преобразуется в длину массива / строки. Так что вместо k=length(A), используйте, A[k=end]чтобы сохранить 3 символа. Обратите внимание, что это может быть не выгодно, если вы хотите использовать k немедленно. Это также работает в многомерном случае - A[k=end,l=end]получит размер каждого измерения A- однако (k,l)=size(A)в этом случае он будет короче на один байт, поэтому используйте его, только если вы хотите сразу получить доступ к последнему элементу одновременно.
Получить итератор индекса с помощью индексации массива - Подобно 13, вы также можете получить итератор, соответствующий длине массива A[k=1:end], в этом случае kбудет выполняться сопоставление итератора 1:length(A). Это может быть полезно, когда вы хотите использовать массив Aодновременно.
Не используйте метод collect для преобразования строки в массив char - вместо этого collect(A)используйте [A...]метод, который сделает то же самое и сэкономит 4 байта.
Нужно преобразовать число в строку? Используйте "$(s[i])"или dec(s[i])для выражений или многосимвольных переменных, и "$i"для односимвольных переменных.
Используйте ?:вместо &&или ||для условного присваивания - то есть, если вы хотите выполнить присваивание только при некотором условии, вы можете сохранить один байт, записав cond?A=B:1вместо cond&&(A=B), или cond?1:A=Bвместо cond||(A=B). Обратите внимание, что 1здесь это фиктивное значение.
Используйте unionили ∪вместоunique - union(s)сделайте то же самое unique(s), что и сохраните байт в процессе. Если вы можете использовать не-ASCII символы, то ∪(s)будете делать то же самое, и ∪стоит всего 3 байта вместо 5 байтов в union.
Переопределенный оператор сохраняет свой первоначальный приоритет.
Обратите внимание, что мы не могли просто поменяться местами !в пользу ~, поскольку ~он уже определен для целых чисел, а !определен только для логических значений.
Бинарные операторы
Даже без рекурсии переопределение оператора короче, чем определение бинарной функции. Сравните следующие определения простого теста делимости.
Не будьте слишком легко соблазнены фактором (n) У заманчивой функции базовой библиотеки factor(n)есть фатальный недостаток: она возвращает факторизацию вашего целого числа в неупорядоченном Dictтипе. Таким образом, для получения данных, которые вы хотели получить , требуются дорогостоящие collect(keys())и, collect(values())потенциально, также catи sort. Во многих случаях может быть дешевле просто учесть фактическое деление. Грустно, но верно.
Использование картыmap - отличная альтернатива зацикливанию. Помните о разнице между mapи map!и используйте функциональные возможности последних, когда это возможно.
Использование mapreducemapreduce расширяет функциональные возможности карты и может значительно сэкономить на байтах.
Анонимные функции великолепны! .. особенно, когда перешли к вышеупомянутым mapфункциям.
Функции кумулятивного массиваcumprod , cumsumароматизатор cumminи другие функции с аналогичными именами обеспечивают кумулятивные операции в указанном измерении n-мерного массива. (Или * un * указано, если массив 1-й)
Краткая запись для Any Если вы хотите выбрать все конкретные измерения многомерного массива (или Dict), например A[Any,2], вы можете сохранить байты с помощьюA[:,2]
Используйте однострочное обозначение для функций. Вместо того, function f(x) begin ... endчтобы часто упрощатьf(x)=(...)
Используйте троичный оператор. Это может быть экономия пространства для конструкций If-Then-Else с одним выражением. Предостережения: Хотя это возможно на некоторых других языках, вы не можете опустить часть после двоеточия в Юлии. Кроме того, в Julia оператор является уровнем выражения, поэтому его нельзя использовать для условного выполнения целых блоков кода. if x<10 then true else false endпротив x<10?true:false
Как на земле «использовать троичный оператор» несколько специфично для Юлии? Это относится к каждому языку, который имеет его.
Питер Тейлор
5
Уместно, что оно есть. Во многих языках также есть карта, анонимные или чистые функции, своего рода сокращение для любых / всех, кумулятивные функции и т. Д. Если бы мы сводили каждую ветку подсказок только к функциям, абсолютно уникальным для этого языка, было бы очень мало содержания подсказок. ,
Джонатан Ван Матре
3
Черт возьми, только все функциональные для начинающих, где все возвращает значение, поэтому троичная операция будет избыточной. Если вам нужны конкретные примеры: Go, Haskell, Scala, Lua, VB, Prolog, PL / SQL ... даже Python не для многих версий. Из почти дюжины языков, в чьих ветках подсказок упоминается их троичный оператор, есть ли какая-то причина, по которой вы решили стать провинциальным в моем?
Джонатан Ван Матре
3
Ну, эй, по крайней мере, ты равнодушный. ヘ ( ̄ ー  ̄ ヘ)
Джонатан Ван Матре
1
Могу ли я предложить изменить совет 3? mapreduce длиннее, чем mapfoldl или mapfoldr, и может иметь различное поведение в зависимости от реализации. mapfoldl и mapfoldr последовательно ассоциируются слева и справа (соответственно) и, таким образом, являются лучшим выбором. Это также относится в целом к уменьшению (используйте foldl или foldr).
Глен О
9
Перебирать функции
Это также возможно в других языках, но обычно дольше, чем простой метод. Тем не менее, способность Джулии переопределить свои унарные и бинарные операторы делает ее довольно гольфы.
Например, чтобы создать таблицу сложения, вычитания, умножения и деления для натуральных чисел от 1 до 10, можно использовать
[x|y for x=1:10,y=1:10,|=(+,-,*,÷)]
который переопределяет бинарный оператор , |как +, -, *и ÷, затем вычисляет x|yдля каждой операции и xи yв желаемых пределах.
Это работает и для унарных операторов. Например, для вычисления комплексных чисел 1 + 2i , 3-4i , -5 + 6i и -7-8i , их негативов, их комплексных конъюгатов и мультипликативных инверсий можно использовать
Ключевые слова иногда могут сразу следовать за константами без необходимости использовать пробел или точку с запятой. Например:
n->(for i=1:n n-=1end;n)
Обратите внимание на отсутствие пробела между 1и end. Это также верно для endпроисходящих после близкого Paren, то есть )end.
Выполните целочисленное деление , используя ÷вместо того , div()или перегрузки оператора. Обратите внимание, что ÷в UTF-8 стоит 2 байта.
Используйте vec()или A[:](для некоторого массива A), а не reshape()когда это возможно.
Создавайте функции, а не полные программы, если это разрешено правилами соревнований Короче определить функцию, которая принимает ввод, а не определять переменные, читая из stdin. Например:
Введено в Юлия 0,5. Это похоже на карту, но использует меньше символов и транслирует поведение по своим аргументам - это означает, что вы можете писать меньше лямбда-выражений, чтобы иметь дело с вещами.
split("Hi there")
поскольку аргумент шаблона по умолчанию равен пробелу.Переопределить операторы для определения функций
Переопределение операторов может сэкономить много байтов в скобках и запятых.
Рекурсивные унарные операторы
Для унарного примера сравните следующие рекурсивные реализации последовательности Фибоначчи:
Попробуйте онлайн!
Переопределенный оператор сохраняет свой первоначальный приоритет.
Обратите внимание, что мы не могли просто поменяться местами
!
в пользу~
, поскольку~
он уже определен для целых чисел, а!
определен только для логических значений.Бинарные операторы
Даже без рекурсии переопределение оператора короче, чем определение бинарной функции. Сравните следующие определения простого теста делимости.
Попробуйте онлайн!
Рекурсивные бинарные операторы
Ниже показано, как переопределить бинарный оператор для вычисления функции Аккермана:
Попробуйте онлайн!
Обратите внимание, что
^
это даже дольше, чем использование обычного идентификатора, поскольку его приоритет слишком высок.Как упоминалось ранее
не будет работать для целочисленных аргументов, так
|
как уже определено в этом случае. Определение целых чисел можно изменить с помощьюно это непомерно долго. Тем не менее, это работает, если мы передаем float в качестве левого аргумента и целое число в качестве правого аргумента.
источник
Не будьте слишком легко соблазнены фактором (n) У заманчивой функции базовой библиотеки
factor(n)
есть фатальный недостаток: она возвращает факторизацию вашего целого числа в неупорядоченномDict
типе. Таким образом, для получения данных, которые вы хотели получить , требуются дорогостоящиеcollect(keys())
и,collect(values())
потенциально, такжеcat
иsort
. Во многих случаях может быть дешевле просто учесть фактическое деление. Грустно, но верно.Использование карты
map
- отличная альтернатива зацикливанию. Помните о разнице междуmap
иmap!
и используйте функциональные возможности последних, когда это возможно.Использование mapreduce
mapreduce
расширяет функциональные возможности карты и может значительно сэкономить на байтах.Анонимные функции великолепны! .. особенно, когда перешли к вышеупомянутым
map
функциям.Функции кумулятивного массива
cumprod
,cumsum
ароматизаторcummin
и другие функции с аналогичными именами обеспечивают кумулятивные операции в указанном измерении n-мерного массива. (Или * un * указано, если массив 1-й)Краткая запись для Any Если вы хотите выбрать все конкретные измерения многомерного массива (или Dict), например
A[Any,2]
, вы можете сохранить байты с помощьюA[:,2]
Используйте однострочное обозначение для функций. Вместо того,
function f(x) begin ... end
чтобы часто упрощатьf(x)=(...)
Используйте троичный оператор. Это может быть экономия пространства для конструкций If-Then-Else с одним выражением. Предостережения: Хотя это возможно на некоторых других языках, вы не можете опустить часть после двоеточия в Юлии. Кроме того, в Julia оператор является уровнем выражения, поэтому его нельзя использовать для условного выполнения целых блоков кода.
if x<10 then true else false end
противx<10?true:false
источник
Перебирать функции
Это также возможно в других языках, но обычно дольше, чем простой метод. Тем не менее, способность Джулии переопределить свои унарные и бинарные операторы делает ее довольно гольфы.
Например, чтобы создать таблицу сложения, вычитания, умножения и деления для натуральных чисел от 1 до 10, можно использовать
который переопределяет бинарный оператор ,
|
как+
,-
,*
и÷
, затем вычисляетx|y
для каждой операции иx
иy
в желаемых пределах.Это работает и для унарных операторов. Например, для вычисления комплексных чисел 1 + 2i , 3-4i , -5 + 6i и -7-8i , их негативов, их комплексных конъюгатов и мультипликативных инверсий можно использовать
который переопределяет унарную оператор ,
~
как+
,-
,conj
иinv
, затем вычисляет~x
для всех желаемых комплексных чисел.Примеры в реальных конкурсах
Женские и мужские последовательности (бинарные)
Case Permutation (одинарный)
источник
Ключевые слова иногда могут сразу следовать за константами без необходимости использовать пробел или точку с запятой. Например:
Обратите внимание на отсутствие пробела между
1
иend
. Это также верно дляend
происходящих после близкого Paren, то есть)end
.Выполните целочисленное деление , используя
÷
вместо того ,div()
или перегрузки оператора. Обратите внимание, что÷
в UTF-8 стоит 2 байта.Используйте
vec()
илиA[:]
(для некоторого массиваA
), а неreshape()
когда это возможно.Создавайте функции, а не полные программы, если это разрешено правилами соревнований Короче определить функцию, которая принимает ввод, а не определять переменные, читая из stdin. Например:
Переменные могут быть увеличены внутри аргумента функции. Например, ниже приведен мой ответ на задачу « Найти следующий 1-разреженный двоичный номер» :
Это короче, чем увеличение
n
внутри цикла.источник
return
f(x)=x+4
идентичен, но корочеf(x)=return x+4
. Юлия всегда возвращает результат последнего утверждения.[x for x in 1:4]
на 3 символа длиннее, но эквивалентно[x for x=1:4]
источник
Используйте функцию трансляции вызовов.
Введено в Юлия 0,5. Это похоже на карту, но использует меньше символов и транслирует поведение по своим аргументам - это означает, что вы можете писать меньше лямбда-выражений, чтобы иметь дело с вещами.
Скорее, чем:
map(f,x)
- 8 символов.f.(x)
- 5 символовЕще лучше:
map(a->g(a,y),x)
- 16 символовg.(x,[y])
- 9 символовисточник