Kiat untuk bermain golf di APL

28

Saya memulai satu tantangan golf kode baru-baru ini dan sepertinya pemenangnya adalah GolfScript (kejutan, kejutan!). Yang menarik adalah bahwa ada pesaing lain yang sangat kuat yang memiliki semua peluang untuk menang atas GolfScript. Namanya APL. Saya melihat banyak jawaban tertulis di APL di sini. Sepertinya bahasa ini cukup efisien untuk golf code, jadi saya memutuskan untuk meminta tips golf code yang Anda tahu untuk program APL. Jangan ragu untuk mengirim beberapa contoh kode. Biasanya sangat menarik untuk melihat bahasa beraksi.

gthacoder
sumber

Jawaban:

23

Sunting : untuk orang yang membaca ini yang sama sekali tidak mengenal APL tetapi ingin mengambilnya, Menguasai Dyalog APL adalah sumber yang sangat bagus.

  1. Evaluasi ketat dari kanan ke kiri. Ini termasuk variabel pengaturan, jadi manfaatkan.

    2+a, 1+a←1 -> 3 4

    adiatur ke 1, 1+adievaluasi ke 2, a,2dievaluasi ke 1 2dan 2+1 2dievaluasi ke 3 4.

  2. Seperti C, dapat dikombinasikan dengan fungsi, yaitu a +← 3. Tidak seperti C, ini generik: foo F← barset fooke F bar. Agak tidak sengaja, sebagai ungkapan ini kembali bar, tidak F bar.

    Ini juga berfungsi dengan fungsi anonim:

          a←0
          a+←3 ⋄ a
    3
          a+←3 ⋄ a
    6
          a { ⍵/'!' } ←4 ⋄ a
    !!!!
    
  3. Anda dapat menetapkan ke array:, A[3]←8seperti yang Anda harapkan. Tetapi Anda juga dapat menetapkan beberapa item sekaligus:, A[3 5 6]←9 1 4atau bahkan A[3 5 6]←9, mengatur semuanya ke item yang sama. Anda tentu saja dapat menambahkan fungsi ke sini juga. Fungsi kemudian akan diterapkan ke setiap elemen secara terpisah, seolah-olah Anda melakukannya .

  4. adalah teman Anda, bahkan jika dia tidak terlihat terlalu senang tentang hal itu.

    1. Jika Fdyadic, dyadic mengganti argumen: a F b<-> b F⍨ a. Ini berguna saat bermain golf karena bisa menyelamatkan Anda dari penggunaan kawat gigi:

      (F G H x) K y      <->     y K⍨ F G H x
      

      Ini memang mengubah urutan evaluasi, karena tangan kanan selalu dievaluasi sebelum tangan kiri.

    2. Jika Fdiad, monadik menerapkan argumen yang sama untuk kedua sisi fungsi:

            5⍴5
      5 5 5 5 5
            ⍴⍨5
      5 5 5 5 5
      

      Argumen hanya dievaluasi satu kali. Ini sangat berguna dengan produk luar, yaitu untuk membandingkan setiap nilai dalam array dengan nilai-nilai lain dalam array yang sama, Anda dapat menggunakan ∘.=⍨daripada harus melakukan x∘.=x←(whatever).

    3. Jika Fbersifat monadik, tidak melakukan apa-apa, tetapi memisahkan fungsi dari argumen. Jadi itu masih bisa menyelamatkan Anda kawat gigi jika fungsinya kompleks:

            {⍵+3}⍣5 6
            ∇{⍵+3}              
           ∇ ⍣ 5 6              
            ({⍵+3}⍣5)6
      21
            {⍵+3}⍣5⍨6
      21
      
  5. Pelajari idiomnya! Lalu mainkan idiom-idiom itu. Sebagai contoh:

    ((((1↑⍴X),⍴Y)↑X)^.=Y)⌿X
    

    secara mekanis dapat diubah menjadi:

    X⌿⍨Y^.=⍨X↑⍨(1↑⍴X),⍴Y
    

    dan kemudian lebih jauh ke:

    X⌿⍨Y^.=⍨X↑⍨(⊃⍴X),⍴Y
    

    (pertama) setara dengan 1↑(ambil satu) dalam hal ini. Dan mungkin:

    X⌿⍨Y^.=⍨X↑⍨(≢X),⍴Y
    

    (penghitungan) setara dengan ⊃⍴(elemen pertama bentuk) untuk semua kecuali skalar.

marinus
sumber
Apakah ada cara untuk mendapatkan lisensi gratis selain memiliki versi raspberry pi?
Fabinout
Cara legal untuk mendapatkannya, jelas.
Fabinout
2
@Fabinout: Di dyalog.com Anda dapat mengunduh versi Windows gratis. Klik "Unduh Zona" dan kemudian "Unduhan Tidak Terdaftar". Ini akan mengganggu Anda untuk mendaftar tetapi selain itu berfungsi penuh dan gratis serta legal. Jika Anda seorang siswa, Anda bisa mendapatkan versi normal secara gratis dengan mengisi formulir. Jika Anda tidak tinggal di negara tempat mereka menghancurkan hidup Anda karena pembajakan, Anda tahu apa yang harus dilakukan.
marinus
Ada juga Nars2000, sebuah implementasi open source yang memiliki lebih banyak fitur daripada Dyalog (dan beberapa bug). Beberapa fiturnya berguna untuk bermain golf, seperti fungsi bilangan prima atau multiset.
Tobia
1
Ada GNU APL.
M. Alaggan
14

Kereta

A(f g h)B      ←→  (A f B)g A h B  ⍝ fork
 (f g h)B      ←→  (  f B)g   h B  ⍝ fork
A(  g h)B      ←→         g A h B  ⍝ atop
 (  g h)B      ←→         g   h B  ⍝ atop
 (A g h)       ←→  ({A} g h)       ⍝ "Agh" fork
 (f g h k)     ←→  (f (g h k))     ⍝ 4-train
 (f g h k l)   ←→  (f g (h k l))   ⍝ 5-train, etc
 (f g h k l m) ←→  (f(g h(k l m))) ⍝ groups of 3 from the right, last could be 2
  f∘g B        ←→    f g B         ⍝ "compose" operator, useful in trains
A f∘g B        ←→  A f g B
ngn
sumber
Apakah itu berarti bahwa demi pembaca masa depan, kita seharusnya tidak memberi tahu Oberon bagaimana mempersingkatnya?
Adám
Tidak, lakukan seperti biasa di PPCG. Saya akan menghapus garis itu setelah ekspresi mencapai (apa yang saya yakini) terpendek. Ini latihan yang mudah - saya tidak berpikir Anda secara pribadi akan mendapat manfaat dari itu.
ngn
Saya bisa menurunkannya menjadi 16, tapi saya tidak menggunakan tips Anda, jadi mungkin saya jauh.
Adám
@ Adám well, Anda menggunakan kereta api :) milik saya serupa tetapi lebih lama karena saya tidak memikirkan ⎕ML
ngn
Bukankah itu "kelompok 3 dari kanan "?
Adam
7

Trik untuk berurusan dengan /dan di kereta

Saat menggunakan kereta, Anda mungkin ingin menggunakan pengurangan f/seperti jumlah +/atau bahkan mereplikasi pengurangan //. Namun, jika kereta Anda memiliki lebih banyak bagian di sebelah kiri reduksi, Anda memerlukan tanda kurung untuk membuat puncak. Berikut adalah beberapa trik untuk menghemat byte.

Gunakan 1∊sebagai ganti monadik ∨/atau ∨⌿pada array Boolean

Tugas: Diberikan dua string sama panjang A dan B, kembalikan 2 jika ada karakter yang sesuai dari A dan B sama, 0 sebaliknya Misalnya A←'abc'dan B←'def'memberikan 0dan A←'abc'dan B←'dec'memberi 2.

Solusi dfn mungkin A{2×∨/⍺=⍵}Btetapi Anda ingin mempersingkat dengan pergi diam-diam. A(2×∨/=)Btidak akan bekerja karena aturan pembentukan kereta mengurai ini 2 (× ∨/ =)tetapi Anda inginkan 2 × (∨/=).

Perhatikan itu ∨/atau ∨⌿pada vektor Boolean ( ∨/,atau ∨⌿,untuk array peringkat yang lebih tinggi) menanyakan apakah ada 1 hadiah, yaitu 1∊, sehingga kita dapat menulis kereta kita sebagai 2×1∊=.

Perhatikan bahwa mengecilkan argumen yang benar, sehingga Anda tidak dapat menggunakannya untuk mengurangi setiap baris atau kolom secara terpisah.

Gunakan 1⊥sebagai ganti monadik +/atau+⌿

Tugas: Diberikan daftar daftar L dan indeks N, kembalikan tiga kali lipat dari jumlah daftar N. Misalnya L←(3 1 4)(2 7)dan N←1memberi 24.

Solusi dfn mungkin N{3×+/⍺⊃⍵}Ltetapi Anda ingin mempersingkat dengan pergi diam-diam. N(3×+/⊃)Ltidak akan bekerja karena aturan pembentukan kereta mengurai ini 3(× +/ ⊃)tetapi Anda inginkan 3 × (+/⊃).

Perhatikan bahwa mengevaluasi daftar angka di unary (basis-1) sama dengan menjumlahkan daftar karena  { a , b , c , d } =  a + b + c + d  = ( a × 1³) + ( b × 1² ) + ( c × 1¹) + ( d × 1⁰). Oleh karena +/a b c ditu sama dengan 1⊥a b c d, dan kita dapat menulis kereta kita sebagai 3×1⊥⊃.

Perhatikan bahwa pada argumen peringkat yang lebih tinggi, 1⊥setara dengan +⌿.

Gunakan f.galih-alih f/gdengan skalar dan / atau argumen vektor

Tugas: Diberikan daftar L dan angka N, kembalikan kisaran 1 dengan teliti jumlah sisa pembagian minimum saat elemen L dibagi dengan NEg L←31 41 59 dan N←7beri 1 2 3.

Solusi dfn mungkin N{⍳⌊/⍺|⍵}Ltetapi Anda ingin mempersingkat dengan pergi diam-diam. N(⍳⌊/|)Ltidak akan bekerja karena aturan pembentukan kereta menguraikan ini sebagai⍳ (⌊/) |tetapi Anda inginkan ⍳ (⌊/|).

Produk dalam A f.g Bskalar dua berfungsi ketika argumennya skalar dan / atau vektor sama dengan f/ A g Bkarena keduanya(A[1] g B[1]) f (A[2] g B[2]) f (A[3] g B[3]) dll, sehingga kita dapat menulis kereta kita sebagai ⍳⌊.|.

Perhatikan bahwa ini tidak berfungsi untuk array peringkat lebih tinggi.

Menggunakan ∊⊆ alih-alih /dengan argumen kanan kanan Boolean dan vektor kanan

Tugas: Diberikan daftar L dan angka N, filter daftar sehingga hanya angka yang lebih besar dari N yang tersisa. Misalnya L←3 1 4danN←1 memberi 3 4.

Solusi dfn mungkin N{(⍺<⍵)/⍵}Ltetapi Anda ingin mempersingkat dengan pergi diam-diam. N(</⊢)Ltidak akan berfungsi karena aturan yang mengikat akan menguraikan ini (</) ⊢tetapi Anda ingin /menjadi fungsi mereplikasi daripada mengurangi operator .

Diadik dengan argumen kiri Boolean mempartisi argumen yang benar sesuai dengan run 1s di argumen kiri, menjatuhkan elemen yang ditunjukkan oleh 0s. Ini hampir apa yang kita inginkan, simpan untuk partisi yang tidak diinginkan. Namun, kita dapat menyingkirkan partisi dengan menerapkan monadik . Dengan demikian {(⍺<⍵)/⍵}dapat menjadi {∊(⍺<⍵)⊆⍵}dan dengan demikian kita dapat menulis kereta kita sebagai ∊<⊆⊢.

Perhatikan bahwa ini tidak berfungsi untuk array peringkat lebih tinggi.

Gunakan 0⊥sebagai ganti ⊢/atau ⊢⌿dengan argumen numerik

Tugas: Diberikan daftar L dan angka N, kalikan N dengan elemen paling kanan dari LEg L←3 1 4dan N←2beri 8.

Solusi dfn mungkin N{⍺×⊢/⍵}Ltetapi Anda ingin mempersingkat dengan pergi diam-diam. N(⊣×⊢/⊢)Ltidak akan bekerja karena aturan pembentukan kereta mengurai ini ⊣ (× ⊢/ ⊢)tetapi Anda inginkan ⊣ × (⊢/⊢).

Perhatikan bahwa 0⊥pada array numerik sama dengan ⊢⌿, jadi kita bisa menulis kereta kita sebagai ⊣×0⊥⊢.

Perhatikan bahwa ini memilih sel utama terakhir dari array peringkat yang lebih tinggi.

Adám
sumber
1
Mungkin Anda bisa menambahkan jawaban obrolan ini ke yang ini?
J. Sallé
1
@ J.Sallé Ditambahkan.
Adám
7

Gunakan untuk menggabungkan multiplikasi dengan tambahan

(a×b)+C  ->  a⊥b,C
(C)+a×b  ->  a⊥b,C
(a×b)-C  ->  a⊥b,-C

Asumsi:

  • adan badalah istilah yang tidak memerlukan tanda kurung lebih lanjut ketika digunakan sebagai argumen kiri

  • C adalah ekspresi yang mungkin membutuhkan tanda kurung ketika digunakan sebagai argumen kiri

  • a b C mengevaluasi skalar numerik

ngn
sumber
5

Bilangan kompleks

Seringkali diabaikan, mereka menghadirkan peluang bagus untuk mempersingkat ekspresi yang berhubungan dengan kisi, labirin, fraktal, atau geometri.

0j1⊥¨    0j1⊥   ⍝ pair(s) of reals -> complex
11 9∘○¨  11 9○  ⍝ complex -> pair(s) of reals
|z0-z1          ⍝ distance between two points
0j1×z   0j¯1×z  ⍝ rotate by ±90° around (0,0)
0j1*⍳4          ⍝ the four cardinal directions
+z       -+z    ⍝ reflect across x or y axis
+\0,z           ⍝ sequence of steps -> path
2-/z            ⍝ path -> sequence of steps
0j1⊥¨n-⍳2⍴1+2×n ⍝ lattice centred on (0,0)
ngn
sumber
4

Pengindeksan panjang vektor modulo

⊃i⌽asering lebih pendek dari naif ⊃a[(≢a)|i]atau a⊃⍨i|⍨≢a(di mana avektor dan ibilangan bulat, dan ⎕io0)

variasi yang berguna untuk ini (terima kasih EriktheOutgolfer untuk menunjukkan) adalah: di I↑Y⌽⍨I×Xmana Yadalah gabungan dari beberapa Ivektor panjang dan Xmerupakan indeks dari yang ingin kita pilih, misalnya:3↑'JanFeb...Dec'⌽⍨3×month

ngn
sumber
3

Fungsi konstan

=⍨dan ≠⍨terima kasih kepada ngn.

Terkadang Anda hanya perlu satu nilai untuk setiap elemen daftar. Meskipun Anda mungkin tergoda untuk menggunakannya {value}¨, ini lebih pendek untuk digunakan value⊣¨ tetapi untuk beberapa nilai umum, Anda bisa menjadi lebih pendek (menggunakan ⎕IO←0):

¯1dengan ⍬⍸list

0dengan ⍬⍳list

1dengan ⍬⍷list

Perhatikan bahwa ini hanya berfungsi pada daftar (meskipun mungkin bersarang). Untuk array peringkat yang lebih tinggi, Anda dapat menggunakan yang berikut untuk mendapatkan semua 0s dan semua 1s:

1dengan =⍨

0dengan ≠⍨

Jika Anda mengatur ⎕ML←0, semua angka dapat dibuat menjadi nol (seolah-olah ) dengan:

Jika Anda hanya membutuhkan satu nomor, Anda dapat menggunakan monadik untuk mendapatkan 1 atau 0 alih-alih menggunakan 1⊣atau 0⊣.

Adám
sumber
" Kadang-kadang Anda hanya perlu nilai tunggal untuk setiap elemen daftar. " - Ini mungkin perlu diperhatikan: ketika nilai itu adalah elemen pertama dari daftar, Anda dapat menggunakan⊣\
ngn
@ Ngn Saya akan mengatakan itu dan dengan /dan pantas posting mereka sendiri.
Adám
2

Menggunakan

Hindari tanda kurung

(Perjalanan) dapat menghemat byte dengan menghindari tanda kurung. Setiap kali Anda memiliki fungsi di mana argumen kiri harus di kurung dan argumen kanan tidak, Anda dapat menyimpan byte, misalnya (A<B)÷CC÷⍨A<B .

Array ganda

Untuk menambahkan salinan array hingga akhir, gunakan ,⍨Aatau ⍪⍨A.

Angka ganda

Alih-alih menggunakan 2∘×untuk menggandakan, Anda dapat menggunakan +⍨karena menambahkan argumen itu sendiri: 1+2∘×1++⍨.

Angka kuadrat

Alih-alih menggunakan 2*⍨Yto square, Anda dapat menggunakan ×⍨Ykarena itu mengalikan argumen dengan dirinya sendiri: 2*⍨A+B×⍨A+B.

Permutasi acak

?⍨Nakan memberi Anda permutasi acak panjang N.

Klasifikasi sendiri

Temukan indeks kemunculan pertama setiap sel utama ⍳⍨A

Hitung trailing 1s dalam vektor Boolean

Alih-alih +/∧\⌽Bmenghitung berapa banyak trailing 1s di dalamnya yang Ndapat Anda gunakan ⊥⍨.

Komposisi terbalik

A f∘g Badalah A f g B, tetapi jika Anda ingin (g A) f B, gunakan f⍨∘g⍨.

Mengurangi mundur

f/ a1 a2 a3adalah a1 f (a2 f a3). Jika Anda ingin (a1 f a2) f a3, gunakanf⍨/⌽ .

Pemindaian terbalik

f\ A B Cadalah
A (A f B) (A f (B f C)).

f⍨/∘⌽¨,\ A B Cadalah
A (A f B) ((A f B) f C).

f⍨\⌽ A B Cadalah
((A f B) f C) (B f C) C.

⌽f/∘⌽¨,\⌽ A B C. adalah
(A f (B f C)) (B f C) C.

Adám
sumber
2

Hitung karakter dalam string tanpa ⍳≢

Tugas: Diberikan dua string, S dan T, daftar indeks gabungan mereka. Misalnya S←'abcd'dan T←'xyz'memberi 1 2 3 4 5 6 7.

Solusi dfn mungkin S{⍳≢⍺,⍵}Ttetapi Anda ingin mempersingkat dengan pergi diam-diam. ⍳≢,tidak akan berfungsi karena aturan parsing kereta akan menguraikan ini seperti yang (⍳)≢(,)Anda inginkan (⍳≢),.

Diad dengan argumen kiri kosong menilai array karakter sederhana menurut urutannya saat ini, yang sama dengan ⍳≢. Dengan demikian {⍳≢⍺,⍵} dapat menjadi {⍬⍋⍺,⍵}, sehingga kita dapat menulis kereta kita sebagai⍬⍋, .

Perhatikan bahwa ini tidak berfungsi untuk array numerik atau campuran.

Adám
sumber
Wow, tidak tahu itu apa-apa.
Zacharý