Conseils pour jouer au golf à APL

28

J'ai commencé un défi de golf de code récemment et il semble que le gagnant soit GolfScript (surprise, surprise!). Ce qui est intéressant, c'est qu'il y avait un autre concurrent très fort qui avait toutes les chances de gagner sur GolfScript. Son nom est APL. Je vois beaucoup de réponses écrites en APL ici. Il semble que ce langage soit assez efficace pour le golf de code, donc je décide de demander des conseils de golf de code que vous connaissez pour les programmes APL. N'hésitez pas à publier quelques exemples de code. Il est généralement très intéressant de voir le langage en action.

gthacoder
la source

Réponses:

23

Edit : pour les personnes qui lisent ceci et qui ne connaissent pas du tout l'APL mais qui veulent s'y mettre, la maîtrise de Dyalog APL est une très bonne ressource.

  1. L'évaluation est strictement de droite à gauche. Cela inclut la définition de variables, alors profitez-en.

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

    aest défini sur 1, 1+aévalue à 2, a,2évalue à 1 2et 2+1 2évalue à 3 4.

  2. Comme C, peut être combiné avec une fonction, ie a +← 3. Contrairement à C, c'est générique: foo F← bardéfinit foosur F bar. Pas assez intuitivement, comme expression cela revient bar, non F bar.

    Il fonctionne également avec des fonctions anonymes:

          a←0
          a+←3 ⋄ a
    3
          a+←3 ⋄ a
    6
          a { ⍵/'!' } ←4 ⋄ a
    !!!!
    
  3. Vous pouvez attribuer à un tableau:, A[3]←8comme vous vous en doutez. Mais vous pouvez également attribuer plusieurs éléments en même temps:, A[3 5 6]←9 1 4ou même A[3 5 6]←9, en les définissant tous sur le même élément. Vous pouvez bien sûr ajouter une fonction ici aussi. La fonction sera ensuite appliquée à chaque élément séparément, comme si vous l'avez fait .

  4. est votre ami, même s'il n'en a pas l'air trop content.

    1. Si Fest dyadique, dyadique change les arguments: a F b<-> b F⍨ a. Cela est pratique lorsque vous jouez au golf, car cela peut vous éviter d'utiliser des accolades:

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

      Cela change l'ordre d'évaluation, car la main droite est toujours évaluée avant la main gauche.

    2. Si Fest dyadique, monadique applique le même argument aux deux côtés de la fonction:

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

      L'argument n'est évalué qu'une seule fois. Cela est particulièrement utile avec les produits externes, c'est-à-dire que pour comparer chaque valeur d'un tableau avec les autres valeurs du même tableau, vous pouvez utiliser ∘.=⍨au lieu de devoir le faire x∘.=x←(whatever).

    3. Si Fest monadique, ne fait rien, mais il sépare la fonction de l'argument. Ainsi, il peut toujours vous sauver des accolades si la fonction est complexe:

            {⍵+3}⍣5 6
            ∇{⍵+3}              
           ∇ ⍣ 5 6              
            ({⍵+3}⍣5)6
      21
            {⍵+3}⍣5⍨6
      21
      
  5. Apprenez les idiomes! Jouez ensuite les idiomes. Par exemple:

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

    peut être transformé mécaniquement en:

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

    puis plus loin dans:

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

    (premier) étant équivalent à 1↑(prendre un) dans ce cas. Et éventuellement:

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

    (tally) étant équivalent à ⊃⍴(le premier élément de la forme) pour tous sauf les scalaires.

marinus
la source
Existe-t-il un moyen d'obtenir une licence gratuite en plus d'avoir la version Raspberry Pi?
Fabinout
Un moyen légal de l'obtenir, évidemment.
Fabinout
2
@Fabinout: Sur dyalog.com, vous pouvez télécharger une version gratuite de Windows. Cliquez sur "Zone de téléchargement" puis sur "Téléchargement non enregistré". Il vous incitera à vous inscrire mais sinon il est entièrement fonctionnel et gratuit et légal. Si vous êtes étudiant, vous pouvez obtenir la version normale gratuitement en remplissant un formulaire. Si vous ne vivez pas dans un pays où ils ruinent votre vie pour le piratage, eh bien, vous savez quoi faire.
marinus
Il y a aussi Nars2000, une implémentation open source qui a beaucoup plus de fonctionnalités que Dyalog (et quelques bugs.) Certaines de ses fonctionnalités sont utiles pour le golf, telles que les fonctions de nombres premiers ou les multisets.
Tobia
1
Il y a GNU APL.
M. Alaggan
14

Les trains

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
la source
Est-ce à dire que pour le bien des futurs lecteurs, il ne faut pas dire à Oberon comment le raccourcir?
2018 à 7h11
Non, faites comme vous le feriez normalement sur PPCG. Je supprimerai cette ligne une fois que l'expression aura atteint (ce que je crois être) sa plus courte. C'est un exercice facile - je ne pense pas que vous en bénéficieriez personnellement.
2018 à 9h29
Je peux le ramener à 16, mais je n'utilise aucun de vos conseils, alors je suis peut-être loin.
Adám
@ Adám bien, vous utilisez un train :) le mien était similaire mais plus long parce que je ne pensais pas à ⎕ML
ngn
N'est-ce pas "des groupes de 3 à droite "?
2018
7

Astuces pour gérer /et dans les trains

Lorsque vous utilisez des trains, vous voudrez peut-être utiliser des réductions f/telles que la somme +/ou même la réplication de réduction// . Cependant, si votre train a plus de pièces à gauche de la réduction, vous avez besoin de parenthèses pour créer un sommet. Voici quelques astuces pour économiser des octets.

Utilisez 1∊au lieu de monadique ∨/ou∨⌿ sur des tableaux booléens

Tâche: étant donné deux chaînes de longueur égale A et B, retournez 2 si tous les caractères correspondants de A et B sont égaux, 0 sinon. Par exemple A←'abc'et B←'def'donne 0et A←'abc'et B←'dec'donne 2.

Une solution dfn peut être A{2×∨/⍺=⍵}Bmais vous voulez la raccourcir en allant tacite. A(2×∨/=)Bne va pas fonctionner parce que les règles de formation des trains analysent cela comme 2 (× ∨/ =)vous le souhaitez 2 × (∨/=).

Observez cela ∨/ou ∨⌿sur un vecteur booléen ( ∨/,ou ∨⌿,pour des tableaux de rang supérieur) demande s'il y a un 1 présent, c'est 1∊-à- dire , afin que nous puissions écrire notre train comme 2×1∊=.

Notez que défile son argument de droite, vous ne pouvez donc pas l'utiliser pour réduire chaque ligne ou colonne séparément.

Utilisez 1⊥au lieu de monadique +/ou+⌿

Tâche: étant donné une liste de listes L et un index N, retournez trois fois la somme de la Nième liste. Par exemple L←(3 1 4)(2 7)et N←1donne 24.

Une solution dfn peut être N{3×+/⍺⊃⍵}Lmais vous voulez la raccourcir en allant tacite. N(3×+/⊃)Lne va pas fonctionner parce que les règles de formation des trains analysent cela comme 3(× +/ ⊃)vous le souhaitez 3 × (+/⊃).

Observez que l'évaluation d'une liste de nombres en unaire (base-1) équivaut à sommer la liste car ∑ { a , b , c , d } =  a + b + c + d  = ( a × 1³) + ( b × 1² ) + ( c × 1¹) + ( d × 1⁰). Par conséquent, +/a b c dc'est la même chose que 1⊥a b c d, et nous pouvons écrire notre train comme 3×1⊥⊃.

Notez que sur les arguments de rang supérieur, 1⊥est équivalent à +⌿.

Utiliser f.gau lieu de f/gavec des arguments scalaires et / ou vectoriels

Tâche: étant donné une liste L et un nombre N, renvoyez la plage 1 jusqu'au nombre de divisions minimales restant lorsque les éléments de L sont divisés par NEg L←31 41 59et N←7donne1 2 3 .

Une solution dfn peut être N{⍳⌊/⍺|⍵}Lmais vous voulez la raccourcir en allant tacite. N(⍳⌊/|)Lne va pas fonctionner parce que les règles de formation des trains analysent cela comme ⍳ (⌊/) |vous le souhaitez ⍳ (⌊/|).

Le produit interne A f.g Bde deux fonctions scalaires lorsque les arguments sont des scalaires et / ou des vecteurs est le même que f/ A g Bparce que les deux sont (A[1] g B[1]) f (A[2] g B[2]) f (A[3] g B[3])etc., donc nous pouvons écrire notre train comme ⍳⌊.|.

Notez que cela ne fonctionne pas pour les tableaux de rang supérieur.

Utiliser ∊⊆au lieu de /avec des arguments booléens gauche et simple vecteur droite

Tâche: étant donné une liste L et un nombre N, filtrez la liste afin qu'il ne reste que des nombres supérieurs à N. Par exemple L←3 1 4et N←1donne 3 4.

Une solution dfn peut être N{(⍺<⍵)/⍵}Lmais vous voulez la raccourcir en faisant tacite. N(</⊢)Lne fonctionnera pas car les règles de liaison analyseront cela comme (</) ⊢mais vous voulez /être la fonction répliquée plutôt que l'opérateur réduire .

Dyadique avec un argument gauche booléen partitionne l'argument droit selon des séries de 1 dans l'argument gauche, supprimant les éléments indiqués par 0. C'est presque ce que nous voulons, sauf pour le partitionnement indésirable. Cependant, nous pouvons nous débarrasser du partitionnement en appliquant monadic . Ainsi {(⍺<⍵)/⍵}peut devenir {∊(⍺<⍵)⊆⍵}et ainsi nous pouvons écrire notre train comme ∊<⊆⊢.

Notez que cela ne fonctionne pas pour les tableaux de rang supérieur.

Utiliser à la 0⊥place ⊢/ou ⊢⌿avec des arguments numériques

Tâche: étant donné une liste L et un nombre N, multipliez le N par l'élément le plus à droite de LEg L←3 1 4et N←2donne 8.

Une solution dfn peut être N{⍺×⊢/⍵}Lmais vous voulez la raccourcir en allant tacite. N(⊣×⊢/⊢)Lne va pas fonctionner parce que les règles de formation des trains analysent cela comme ⊣ (× ⊢/ ⊢)vous le souhaitez ⊣ × (⊢/⊢).

Observez que 0⊥sur un tableau numérique est le même que ⊢⌿, afin que nous puissions écrire notre train comme ⊣×0⊥⊢.

Notez que cela sélectionne la dernière cellule principale des tableaux de rang supérieur.

Adam
la source
1
Peut-être pourriez-vous ajouter cette réponse de chat à celle-ci?
J.Sallé
1
@ J.Sallé Ajouté.
Adám
7

Utilisez pour combiner la multiplication avec l'addition

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

Hypothèses:

  • aet bsont des termes qui ne nécessitent pas de parenthèses supplémentaires lorsqu'ils sont utilisés comme argument de gauche

  • C est une expression qui peut nécessiter des parenthèses lorsqu'elle est utilisée comme argument de gauche

  • a b C évaluer en scalaires numériques

ngn
la source
5

Nombres complexes

Souvent négligés, ils offrent de merveilleuses opportunités pour raccourcir les expressions traitant des grilles, des labyrinthes, des fractales ou de la géométrie.

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
la source
4

Indexation de la longueur du vecteur modulo

⊃i⌽aest souvent plus court que le naïf ⊃a[(≢a)|i]ou a⊃⍨i|⍨≢a(où aest un vecteur et iest un entier, et ⎕ioest 0)

une variation utile à ce sujet (merci EriktheOutgolfer pour avoir souligné) est: I↑Y⌽⍨I×XYest la concaténation de certains Ivecteurs de longueur et Xest l'indice de celui que nous voulons choisir, par exemple:3↑'JanFeb...Dec'⌽⍨3×month

ngn
la source
3

Fonctions constantes

=⍨et ≠⍨merci à ngn.

Parfois, vous n'avez besoin que d'une seule valeur pour chaque élément d'une liste. Bien que vous puissiez être tenté d'utiliser {value}¨, il est plus court à utiliser, value⊣¨ mais pour certaines valeurs courantes, vous pouvez obtenir encore plus court (en utilisant ⎕IO←0):

¯1s avec ⍬⍸list

0s avec ⍬⍳list

1s avec ⍬⍷list

Notez que ceux-ci ne fonctionnent que sur les listes (bien qu'ils puissent être imbriqués). Pour les tableaux de rang supérieur, vous pouvez utiliser ce qui suit pour obtenir tous les 0 et tous les 1:

1s avec =⍨

0s avec ≠⍨

Si vous définissez ⎕ML←0, tous les nombres peuvent être transformés en zéros (comme si ) avec:

Si vous n'avez besoin que d'un seul numéro, vous pourrez peut-être utiliser monadic pour obtenir 1 ou 0 au lieu d'utiliser 1⊣ou 0⊣.

Adam
la source
" Parfois, vous avez juste besoin d'une seule valeur pour chaque élément d'une liste. " - Cela peut être intéressant: lorsque cette valeur est le premier élément de la liste, vous pouvez utiliser⊣\
ngn
@ngn Je dirais cela et avec /et mérite un poste à part.
Adám
2

Utilisation

Évitez les parenthèses

(Commute) peut vous faire économiser des octets en évitant les parenthèses. Chaque fois que vous avez une fonction où l'argument de gauche doit être mis entre parenthèses et pas celui de droite, vous pouvez enregistrer un octet, par exemple (A<B)÷CC÷⍨A<B.

Tableaux doubles

Pour ajouter une copie d'un tableau à sa fin, utilisez ,⍨Aou ⍪⍨A.

Numéros doubles

Au lieu d'utiliser 2∘×pour doubler, vous pouvez utiliser +⍨car il ajoute l'argument à lui-même: 1+2∘×1++⍨.

Numéros carrés

Au lieu d'utiliser 2*⍨Ycarré, vous pouvez utiliser ×⍨Ycar il multiplie l'argument par lui-même: 2*⍨A+B×⍨A+B.

Permutation aléatoire

?⍨Nvous donnera une permutation aléatoire de la longueur N.

Auto-classification

Trouvez les indices de la première occurrence de chaque cellule principale avec ⍳⍨A

Compter les 1 de fin dans un vecteur booléen

Au lieu de +/∧\⌽Bcompter le nombre de 1 en fin, Nvous pouvez utiliser ⊥⍨.

Composition inversée

A f∘g Best A f g B, mais si vous voulez (g A) f B, utilisez f⍨∘g⍨.

Inverser réduire

f/ a1 a2 a3est a1 f (a2 f a3). Si vous le souhaitez (a1 f a2) f a3, utilisez f⍨/⌽.

Balayage inversé

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

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

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

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

Adam
la source
2

Énumérer les caractères d'une chaîne sans ⍳≢

Tâche: étant donné deux chaînes, S et T, listez les indices de leur concaténation. Par exemple S←'abcd'et T←'xyz'donne 1 2 3 4 5 6 7.

Une solution dfn peut être S{⍳≢⍺,⍵}Tmais vous voulez la raccourcir en faisant tacite. ⍳≢,ne va pas fonctionner car les règles d'analyse du train analyseront ceci comme (⍳)≢(,)vous le souhaitez (⍳≢),.

Dyadique avec un argument gauche vide classe les tableaux de caractères simples selon leur ordre actuel, qui est le même que ⍳≢. Ainsi {⍳≢⍺,⍵} peut devenir {⍬⍋⍺,⍵}, afin que nous puissions écrire notre train comme ⍬⍋,.

Notez que cela ne fonctionne pas pour les tableaux numériques ou mixtes.

Adam
la source
Wow, je ne savais pas que c'était une chose.
Zacharý