Какие общие советы у вас есть для игры в гольф в Юлии? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, которые, по крайней мере, несколько специфичны для Джулии (например, «удалить комментарии» - это не ответ).
Какие общие советы у вас есть для игры в гольф в Юлии? Я ищу идеи, которые могут быть применены к кодовым проблемам гольфа в целом, которые, по крайней мере, несколько специфичны для Джулии (например, «удалить комментарии» - это не ответ).
Ответы:
ПРИМЕЧАНИЕ: ниже могут содержаться некоторые устаревшие советы, так как Юлия еще не совсем стабилизировалась с точки зрения структуры.
Несколько трюков, чтобы сохранить несколько персонажей
\ =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
, сохраняя три байта для каждого использования, за счет всего двух дополнительных символов при назначении. Очевидно, не делайте этого, если вы можете работать с векторными операциями.[]
- для массивов, выражение A[]
эквивалентно A[1]
. Обратите внимание, что это не работает для строк, если вы хотите получить первый символ, или для кортежей.==[]
для массивов и ==()
кортежей; аналогично для негатива используйте !=[]
и !=()
. Для строк, используйте ==""
для пустого, но используйте >""
для не пустого, так как "" лексикографически перед любой другой строкой.x<=1&&"Hi"
можно записать как x>1||"Hi"
сохранение символа (если возвращение логического значения не имеет значения).in('^',s)
вместо contains(s,"^")
. Если вы можете использовать другие символы, вы можете сэкономить немного больше '^'∈s
, но учтите, что ∈
в UTF-8 это 3 байта.minimum(x)
или maximum(x)
, используйте min(x...)
или max(x...)
, чтобы убрать один символ из вашего кода, если вы знаете, x
будет иметь по крайней мере два элемента. В качестве альтернативы, если вы знаете, что все элементы x
будут неотрицательными, используйте minabs(x)
илиmaxabs(x)
r"(?m)match^ this"
, печатайте r"match^ this"m
, сохраняя три символа.reverse(x)
на один байт длиннее flipud(x)
и будут выполнять ту же операцию, поэтому последний лучше.{[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)
в этом случае он будет короче на один байт, поэтому используйте его, только если вы хотите сразу получить доступ к последнему элементу одновременно.A[k=1:end]
, в этом случае k
будет выполняться сопоставление итератора 1:length(A)
. Это может быть полезно, когда вы хотите использовать массив A
одновременно.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
.split("Hi there")
поскольку аргумент шаблона по умолчанию равен пробелу.
Переопределение операторов может сэкономить много байтов в скобках и запятых.
Для унарного примера сравните следующие рекурсивные реализации последовательности Фибоначчи:
F(n)=n>1?F(n-1)+F(n-2):n # 24 bytes
!n=n>1?!~-n+!(n-2):n # 20 bytes
!n=n>1?!~-n+!~-~-n:n # 20 bytes
Переопределенный оператор сохраняет свой первоначальный приоритет.
Обратите внимание, что мы не могли просто поменяться местами !
в пользу ~
, поскольку ~
он уже определен для целых чисел, а !
определен только для логических значений.
Даже без рекурсии переопределение оператора короче, чем определение бинарной функции. Сравните следующие определения простого теста делимости.
f(x,y)=x==0?y==0:y%x==0 # 23 bytes
(x,y)->x==0?y==0:y%x==0 # 23 bytes
x->y->x==0?y==0:y%x==0 # 22 bytes
x\y=x==0?y==0:y%x==0 # 20 bytes
Ниже показано, как переопределить бинарный оператор для вычисления функции Аккермана:
A(m,n)=m>0?A(m-1,n<1||A(m,n-1)):n+1 # 35 bytes
^ =(m,n)->m>0?(m-1)^(n<1||m^~-n):n+1 # 36 bytes
| =(m,n)->m>0?m-1|(n<1||m|~-n):n+1 # 34 bytes
m\n=m>0?~-m\(n<1||m\~-n):n+1 # 28 bytes
Обратите внимание, что ^
это даже дольше, чем использование обычного идентификатора, поскольку его приоритет слишком высок.
Как упоминалось ранее
m|n=m>0?m-1|(n<1||m|~-n):n+1 # 28 bytes
не будет работать для целочисленных аргументов, так |
как уже определено в этом случае. Определение целых чисел можно изменить с помощью
m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes
но это непомерно долго. Тем не менее, это работает, если мы передаем 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 for x=1:10,y=1:10,| =(+,-,*,÷)]
который переопределяет бинарный оператор , |
как +
, -
, *
и ÷
, затем вычисляет x|y
для каждой операции и x
и y
в желаемых пределах.
Это работает и для унарных операторов. Например, для вычисления комплексных чисел 1 + 2i , 3-4i , -5 + 6i и -7-8i , их негативов, их комплексных конъюгатов и мультипликативных инверсий можно использовать
[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]
который переопределяет унарную оператор , ~
как +
, -
, conj
и inv
, затем вычисляет ~x
для всех желаемых комплексных чисел.
Женские и мужские последовательности (бинарные)
Case Permutation (одинарный)
Ключевые слова иногда могут сразу следовать за константами без необходимости использовать пробел или точку с запятой. Например:
n->(for i=1:n n-=1end;n)
Обратите внимание на отсутствие пробела между 1
и end
. Это также верно для end
происходящих после близкого Paren, то есть )end
.
Выполните целочисленное деление , используя ÷
вместо того , div()
или перегрузки оператора. Обратите внимание, что ÷
в UTF-8 стоит 2 байта.
Используйте vec()
или A[:]
(для некоторого массива A
), а не reshape()
когда это возможно.
Создавайте функции, а не полные программы, если это разрешено правилами соревнований Короче определить функцию, которая принимает ввод, а не определять переменные, читая из stdin. Например:
n->(n^2-1)
n=read(STDIN,Int);n^2-1
Переменные могут быть увеличены внутри аргумента функции. Например, ниже приведен мой ответ на задачу « Найти следующий 1-разреженный двоичный номер» :
n->(while contains(bin(n+=1),"11")end;n)
Это короче, чем увеличение n
внутри цикла.
Введено в Юлия 0,5. Это похоже на карту, но использует меньше символов и транслирует поведение по своим аргументам - это означает, что вы можете писать меньше лямбда-выражений, чтобы иметь дело с вещами.
Скорее, чем:
map(f,x)
- 8 символов.f.(x)
- 5 символовЕще лучше:
map(a->g(a,y),x)
- 16 символовg.(x,[y])
- 9 символов