Tips untuk bermain golf di Julia

20

Tips umum apa yang Anda miliki untuk bermain golf di Julia? Saya mencari ide yang dapat diterapkan pada masalah kode golf secara umum yang setidaknya agak spesifik untuk Julia (mis. "Hapus komentar" bukan jawaban).

Jonathan Van Matre
sumber

Jawaban:

19

CATATAN: Di bawah ini mungkin berisi beberapa tips yang sudah ketinggalan zaman, karena Julia belum cukup stabil dalam hal struktur, belum.

Beberapa trik untuk menyimpan beberapa karakter

  1. Kelebihan operator dengan fungsi biner yang sering digunakan . Misalnya, jika Anda perlu untuk melakukan banyak divisi integer, dan tidak perlu untuk divisi terbalik, penggunaan \ =div, dan Anda kemudian dapat mengetik a\bbukan div(a,b). Perhatikan ruang - ini diperlukan untuk menghindari penguraian sebagai operator "\ =". Juga perhatikan bahwa, jika kelebihan beban pada level REPL prompt, gunakan (\)=Base.(\)atau \ =Base. \untuk meresetnya. CATATAN: beberapa fungsi memiliki operator UTF-8 yang sudah ditentukan sebelumnya, seperti ÷untuk div, seperti yang dicatat oleh Alex A.
  2. Gunakan ^ dengan string untuk output bersyarat . Artinya, alih-alih a>0?"Hi":"", gunakan "Hi"^(a>0)untuk menyimpan satu byte, atau untuk boolean a, gunakan "Hi"^auntuk menyimpan tiga byte.
  3. (Kadang-kadang) Simpan vektor ukuran tetap kecil sebagai variabel terpisah . Misalnya, alih-alih a=split("Hi there"," "), Anda mungkin dapat menghindari a[1]dan a[2]menggunakan a,b=split("Hi there"," "), yang dapat dirujuk sebagai adan b, menghemat tiga byte untuk setiap penggunaan, dengan biaya hanya dua karakter tambahan saat penugasan. Jelas, jangan lakukan ini jika Anda dapat bekerja dengan operasi vektor.
  4. Akses elemen pertama Array dengan[] - untuk array, ekspresi A[]sama dengan A[1]. Perhatikan bahwa ini tidak berfungsi untuk Strings jika Anda ingin mendapatkan karakter pertama, atau untuk Tuples.
  5. Jangan gunakan isempty untuk Array, Tuples, atau Strings - sebagai gantinya, gunakan ==[]untuk array dan ==()untuk tuple; sama halnya, untuk yang negatif, gunakan !=[]dan !=(). Untuk string, gunakan ==""untuk kosong, tetapi gunakan >""untuk tidak-kosong, karena "" secara leksikografis sebelum string lain.
  6. Gunakan operator boolean hubung singkat yang tepat untuk menggantikan "jika" . Mungkin agak kurang spesifik untuk Julia, tetapi perlu diingat. x<=1&&"Hi"dapat ditulis sebagai x>1||"Hi", menyimpan karakter (selama kembalinya boolean tidak penting).
  7. Jangan gunakan berisi untuk memeriksa keberadaan karakter dalam string - jika Anda terbatas pada ASCII dasar, gunakan in('^',s)daripada contains(s,"^"). Jika Anda dapat menggunakan karakter lain, Anda dapat menyimpan sedikit lebih banyak dengan '^'∈s, tetapi perhatikan bahwa 3 byte di UTF-8.
  8. Mencari nilai minimum / maksimum dalam sebuah array? Jangan gunakan minimum atau maksimum - daripada menggunakan minimum(x)atau maximum(x), menggunakan min(x...)atau max(x...), untuk mencukur satu karakter dari kode Anda, jika Anda tahu xakan memiliki setidaknya dua elemen. Atau, jika Anda tahu semua elemen xakan non-negatif, gunakan minabs(x)ataumaxabs(x)
  9. Jika memungkinkan dan diizinkan oleh tantangan, gunakan baris baru yang sebenarnya alih-alih \ n - perhatikan bahwa ini akan membuat kode Anda lebih sulit untuk dibaca, dan mungkin berarti Anda perlu menyediakan versi "yang tidak diklik" untuk memungkinkan orang benar-benar memahami saya t.
  10. Masukkan opsi setelah string regex - jika Anda ingin memiliki string regex dalam mode multiline, misalnya, jangan mengetik r"(?m)match^ this", mengetik r"match^ this"m, menyimpan tiga karakter.
  11. Membalikkan array 1-D menggunakan flipud - reverse(x)lebih panjang satu byte daripada flipud(x)dan akan melakukan operasi yang sama, sehingga yang terakhir lebih baik.
  12. Jika memungkinkan, gunakan rangkaian array alih-alih dorong !, unshift !, append !, atau tambahkan! - untuk array normal, ini bisa dilakukan dengan mudah. Untuk array tipe Any dengan elemen array, Anda perlu tanda kurung keriting di sekitar array yang ditambahkan (yaitu {[1,2]}, tidak {1,2}) - untuk Julia 0.4, Anda perlu Any[[1,2]].
  13. Gunakan pengindeksan array untuk mendapatkan ukuran array atau string - ketika Anda menggunakan enddalam pengindeksan array, secara otomatis akan dikonversi ke panjang array / string. Jadi alih-alih k=length(A), gunakan A[k=end]untuk menyimpan 3 karakter. Perhatikan bahwa ini mungkin tidak bermanfaat jika Anda ingin segera menggunakan k. Ini juga berfungsi dalam kasus multidimensi - A[k=end,l=end]akan mendapatkan ukuran setiap dimensi A- namun, (k,l)=size(A)lebih pendek satu byte dalam kasus ini, jadi gunakan hanya jika Anda ingin segera mengakses elemen terakhir pada saat yang sama.
  14. Dapatkan indeks iterator menggunakan pengindeksan array - Mirip dengan 13, Anda juga dapat memperoleh iterator yang cocok dengan panjang array yang digunakan A[k=1:end], dalam hal ini kakan memegang pencocokan iterator 1:length(A). Ini bisa berguna ketika Anda ingin juga menggunakan array Apada saat yang bersamaan.
  15. Jangan gunakan kumpulkan untuk mengonversi string menjadi array char - alih-alih collect(A), gunakan [A...], yang akan melakukan hal yang sama dan menyimpan 4 byte.
  16. Perlu nomor yang dikonversi ke string? Gunakan "$(s[i])"atau dec(s[i])untuk ekspresi atau variabel multi-karakter, dan "$i"untuk variabel-karakter tunggal.
  17. Gunakan ?:alih-alih &&atau ||untuk penugasan bersyarat - yaitu, jika Anda ingin melakukan penugasan hanya pada kondisi tertentu, Anda dapat menyimpan satu byte dengan menulis cond?A=B:1daripada cond&&(A=B), atau cond?1:A=Bbukannya cond||(A=B). Perhatikan bahwa 1, di sini, adalah nilai dummy.
  18. Gunakan unionatau bukannyaunique - union(s)akan melakukan hal yang sama seperti unique(s), dan menyimpan byte dalam proses. Jika Anda dapat menggunakan karakter non-ASCII, maka ∪(s)akan melakukan hal yang sama, dan hanya biaya 3 byte, bukan 5 byte union.
Glen O
sumber
2
Oh betapa aku akan sangat menyukai trik pertama dengan Python.
seequ
Anda dapat membagi pada spasi menggunakan hanya split("Hi there")karena argumen pola default ke spasi.
Alex A.
@AlexA. - Saya tahu, tapi itu bukan inti dari tip, dan tip berlaku sama baiknya.
Glen O
Poin 12 telah berubah dalam 0,5.
Lyndon White
@Oxinabox - Saya tidak terkejut, saya cukup yakin beberapa dari mereka sudah ketinggalan zaman sekarang. Saya awalnya menulis sebagian besar tips untuk 0,3, saya pikir.
Glen O
15

Definisikan ulang operator untuk menetapkan fungsi

Mendefinisikan ulang operator dapat menyimpan banyak byte dalam tanda kurung dan koma.

Operator unary rekursif

Sebagai contoh unary, bandingkan implementasi rekursif dari urutan Fibonacci berikut:

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

Cobalah online!

Operator yang didefinisikan ulang mempertahankan prioritas awal.

Perhatikan bahwa kita tidak bisa sekadar bertukar !demi ~, karena ~sudah ditentukan untuk bilangan bulat, sementara !hanya ditentukan untuk Boolean.

Operator biner

Bahkan tanpa rekursi, mendefinisikan ulang operator lebih pendek daripada mendefinisikan fungsi biner. Bandingkan definisi tes keterpisahan sederhana berikut.

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

Cobalah online!

Operator biner rekursif

Berikut ini menggambarkan cara mendefinisikan ulang operator biner untuk menghitung fungsi Ackermann:

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

Cobalah online!

Perhatikan bahwa ^ini lebih lama daripada menggunakan pengenal biasa, karena prioritasnya terlalu tinggi.

Seperti disebutkan sebelumnya

m|n=m>0?m-1|(n<1||m|~-n):n+1           # 28 bytes

tidak akan berfungsi untuk argumen integer, karena |sudah ditentukan dalam kasus ini. Definisi untuk bilangan bulat dapat diubah dengan

m::Int|n::Int=m>0?m-1|(n<1||m|~-n):n+1 # 38 bytes

tapi itu terlalu lama. Namun, tidak bekerja jika kita melewati pelampung sebagai argumen kiri dan integer sebagai argumen yang tepat.

Dennis
sumber
11
  1. Jangan terlalu mudah tergoda oleh faktor (n) Fungsi pustaka basis yang menggoda factor(n)memiliki kelemahan fatal: ia mengembalikan faktorisasi bilangan bulat Anda dalam Dicttipe yang tidak berurutan . Dengan demikian, itu memerlukan biaya collect(keys())dan collect(values())dan berpotensi juga a catdan a sortuntuk mendapatkan data yang Anda inginkan. Dalam banyak kasus, mungkin lebih murah untuk hanya faktor dengan pembagian percobaan. Sedih, tapi benar.

  2. Gunakan peta map adalah alternatif yang bagus untuk perulangan. Waspadai perbedaan antara mapdan map!dan manfaatkan fungsionalitas in-place yang terakhir ketika Anda bisa.

  3. Gunakan mapreduce mapreduce memperluas fungsionalitas peta lebih jauh dan bisa menjadi byte-saver yang signifikan.

  4. Fungsi anonim sangat bagus! ..terutama ketika diteruskan ke mapfungsi yang disebutkan di atas .

  5. Fungsi array kumulatif cumprod , cumsum, yang beraroma cummindan fungsi lainnya bernama sama memungkinkan operasi kumulatif sepanjang dimensi tertentu dari sebuah array n-dimensi. (Atau * tidak * ditentukan jika arraynya 1-d)

  6. Notasi singkat untuk Apa saja Ketika Anda ingin memilih semua dimensi tertentu dari array multi-dimensi (atau Diktik), misalnya A[Any,2], Anda dapat menyimpan byte dengan menggunakanA[:,2]

  7. Gunakan notasi satu-baris untuk fungsi, alih-alih function f(x) begin ... endAnda sering dapat menyederhanakannyaf(x)=(...)

  8. Gunakan operator ternary. Ini bisa menjadi penghemat ruang untuk konstruksi ekspresi If-Then-Else ekspresi tunggal. Peringatan: Meskipun mungkin dalam beberapa bahasa lain, Anda tidak dapat menghilangkan bagian setelah titik dua di Julia. Selain itu, operator adalah level ekspresi dalam Julia, jadi Anda tidak dapat menggunakannya untuk eksekusi kode blok secara keseluruhan.
    if x<10 then true else false endvs.
    x<10?true:false

Jonathan Van Matre
sumber
3
Bagaimana mungkin "gunakan operator ternary" agak khusus untuk Julia? Ini relevan untuk setiap bahasa yang memilikinya.
Peter Taylor
5
Sangat relevan untuk memilikinya. Banyak bahasa juga memiliki peta, fungsi anonim atau murni, semacam singkatan untuk semua / semua, fungsi kumulatif, dll. Jika kita ingin mengurangi setiap utas kiat menjadi hanya fitur yang benar-benar unik untuk bahasa itu, akan ada sangat sedikit kiat konten .
Jonathan Van Matre
3
Astaga, hanya semua yang fungsional sebagai permulaan, di mana semuanya mengembalikan nilai sehingga op ternary akan menjadi redundan. Jika Anda harus memiliki contoh spesifik: Buka, Haskell, Scala, Lua, VB, Prolog, PL / SQL ... bahkan Python tidak untuk banyak versi. Dari hampir selusin bahasa yang utasnya menyebutkan operator ternary mereka, adakah alasan mengapa Anda hanya memilih untuk menjadi provinsi di tambang?
Jonathan Van Matre
3
Ya, hei, setidaknya Anda adalah kurmudge dengan kesempatan yang sama. ヘ ( ̄ ー  ̄ ヘ)
Jonathan Van Matre
1
Bisakah saya menyarankan untuk menyesuaikan tip 3? mapreduce lebih panjang dari mapfoldl atau mapfoldr, dan dapat memiliki perilaku yang bervariasi tergantung pada implementasi. mapfoldl dan mapfoldr adalah asosiatif kiri dan kanan (masing-masing) secara konsisten, dan karenanya merupakan pilihan yang lebih baik. Ini juga berlaku lebih umum untuk mengurangi (gunakan foldl atau foldr).
Glen O
9

Iterate alih fungsi

Ini juga dimungkinkan dalam bahasa lain, tetapi biasanya lebih lama dari metode yang sederhana. Namun, kemampuan Julia untuk mendefinisikan kembali operator unary dan biner membuatnya cukup golf.

Misalnya, untuk menghasilkan tabel penambahan, pengurangan, perkalian, dan pembagian untuk bilangan asli dari 1 hingga 10, orang dapat menggunakan

[x|y for x=1:10,y=1:10,| =(+,-,*,÷)]

yang telah mengubah biner Operator |sebagai +, -, *dan ÷, kemudian menghitung x|yuntuk setiap operasi dan xdan ydalam rentang yang diinginkan.

Ini juga berfungsi untuk operator unary. Misalnya, untuk menghitung bilangan kompleks 1 + 2i , 3-4i , -5 + 6i dan -7-8i , negatifnya, konjugat kompleksnya dan inversi multiplikatifnya, orang dapat menggunakan

[~x for~=(+,-,conj,inv),x=(1+2im,3-4im,-5+6im,-7-8im)]

yang telah mengubah unary operator yang ~sebagai +, -, conjdan inv, kemudian menghitung ~xuntuk semua bilangan kompleks yang diinginkan.

Contoh dalam kontes yang sebenarnya

Dennis
sumber
6
  1. Kata kunci terkadang dapat langsung mengikuti konstanta tanpa perlu spasi atau titik koma. Sebagai contoh:

    n->(for i=1:n n-=1end;n)

    Perhatikan kurangnya ruang antara 1dan end. Ini juga berlaku untuk endterjadi setelah paren dekat, yaitu )end.

  2. Lakukan pembagian integer menggunakan ÷alih - alih div()atau kelebihan operator. Perhatikan bahwa ÷bernilai 2 byte dalam UTF-8.

  3. Gunakan vec()atau A[:](untuk beberapa larik A) daripada reshape()bila memungkinkan.

  4. Buat fungsi daripada program lengkap bila diizinkan dalam aturan tantangan. Lebih pendek untuk mendefinisikan fungsi yang menerima input daripada mendefinisikan variabel dengan membaca dari stdin. Sebagai contoh:

    n->(n^2-1)
    n=read(STDIN,Int);n^2-1
  5. Variabel dapat ditambahkan di dalam argumen ke fungsi. Misalnya, berikut ini adalah jawaban saya untuk tantangan Find the Binary Number 1-Sparse Next :

    n->(while contains(bin(n+=1),"11")end;n)

    Ini lebih pendek daripada menambah nbagian dalam loop.

Alex A.
sumber
6
  1. Tipe janganreturn f(x)=x+4 identik tetapi lebih pendek dari f(x)=return x+4. Julia selalu mengembalikan hasil dari pernyataan terakhir.
  2. Gunakan = bukan di . [x for x in 1:4]lebih dari 3 karakter, tetapi setara dengan[x for x=1:4]
gggg
sumber
5

Gunakan panggilan fungsi Siaran.

Diperkenalkan di Julia 0.5. Itu seperti peta, tetapi menggunakan lebih sedikit karakter, dan tidak menyiarkan perilaku di atas itu args - yang berarti Anda dapat menulis lebih sedikit lambda untuk menangani hal-hal.

Daripada:

  • map(f,x) - 8 karakter.
  • f.(x) - 5 karakter

Lebih baik lagi:

  • map(a->g(a,y),x) - 16 karakter
  • g.(x,[y]) - 9 karakter
Lyndon White
sumber