Ceci est une question de astuce pour jouer au golf en Python.
En golf Python, il est courant qu'une soumission soit une fonction définie comme un lambda. Par exemple,
f=lambda x:0**x or x*f(x-1)
calcule la factorielle de x.
Le format lambda présente deux grands avantages :
- Le passe-partout de
f=lambda x:...
oulambda x:...
est plus court que ledef f(x):...return...
oux=input()...print...
- Un appel récursif peut être utilisé pour effectuer une boucle avec une légère surcharge d'octet.
Cependant, les lambdas ont le gros inconvénient de ne permettre qu'une seule expression, aucune déclaration. En particulier, cela ne signifie aucune tâche comme c=chr(x+65)
. C'est problématique quand on a une expression longue dont la valeur doit être référencée deux fois (ou plus).
Des assignations comme E=enumerate
sont possibles en dehors de la fonction ou en tant qu'argument optionnel, mais uniquement si elles ne dépendent pas des entrées de la fonction. Des arguments facultatifs tels que f=lambda n,k=min(n,0):...
fail, car l’entrée n
n’a pas été définie lorsqu’elle k
est évaluée au moment de la définition.
Le résultat est que, parfois, vous aspirez à répéter une longue expression dans un lambda parce que l'alternative est un long non-lambda.
lambda s:s.strip()+s.strip()[::-1]
def f(s):t=s.strip();print t+t[::-1]
Le seuil de rentabilité est d'environ 11 caractères ( détails ), au-delà duquel vous passez en a def
ou program
. Comparez ceci au seuil de rentabilité habituel de longueur 5 pour une expression répétée:
range(a)+range(b)
r=range;r(a)+r(b)
print s[1:],s[1:]*2
r=s[1:];print r,r*2
D'autres langues ont des solutions de contournement, Octave par exemple . Il existe des astuces connues pour Python, mais elles sont longues, maladroites et / ou à usage limité. Une méthode courte et polyvalente pour simuler une assignation dans un lambda révolutionnerait le golf Python.
Quels sont les moyens pour un golfeur Python de surmonter ou de contourner cette limitation? Quelles idées potentielles devraient avoir à l'esprit lorsqu'ils voient une longue expression répétée deux fois dans un lambda?
Mon objectif avec cette question de conseils est de plonger profondément dans ce problème et:
- Cataloguez et analysez les solutions de contournement au golf pour créer une fausse affectation dans un lambda
- Explorez de nouvelles pistes pour de meilleures méthodes
Chaque réponse doit expliquer une solution de contournement ou une piste potentielle.
lambda s:(s+s[::-1]).lower()
. Bien sûr, cela ne répond pas à la question.strip
.Réponses:
eval
Cela n’est pas si important en soi, mais si votre solution utilise déjà
eval
d’une manière ou d’une autre, vous pouvez généralement utiliser cette technique.la source
Expressions d'affectation dans Python 3.8
Python 3.8 ( TIO ) introduit les expressions d’affectation , qui permettent
:=
d’affecter une variable en ligne à une expression.Ceci peut être utilisé dans un
lambda
environnement où les tâches ne sont généralement pas autorisées. Comparer:Voir cette astuce pour plus.
la source
Lambdas intérieurs
Celles-ci vous permettent de définir plusieurs variables à la fois.
contre.
est beaucoup plus long, mais si vous avez plusieurs variables, ou des variables plus longues, qui se répètent plusieurs fois:
contre.
Nombre de caractères
Initial:
(lambda:)()
(11 octets)Première variable:
[space]a
(2 octets)Variables suivantes:
,b,
(3 octets)Utilisation:
a
(1 octet).(Enregistre également sur des crochets)
Donc, cela prend des
3n + 10
octets, oùn
est le nombre de variables. Ceci est un coût initial élevé, mais peut porter ses fruits à la fin. Il retourne même sa valeur intérieure, de sorte que vous pouvez imbriquer plusieurs (Bien que cela deviendra vite pas la peine.)Ceci n'est utile que pour les calculs intermédiaires longs dans les interprétations de listes imbriquées, car
def f():a=...;b=...;return
sa durée est généralement plus courte.Pour 1 valeur, cela enregistre:,
uses * length - length - uses - 13
donc n'est utile que lorsque cette expression est positive.Pour
n
des expressions différentesu
fois utilisées au total, où leur longueur combinée estl
, cela économise:l - (3 * n) - u - 10 ( + brackets removed )
la source
Utiliser une liste
Déclarer une liste en paramètre et utiliser
.append() or
pour stocker la valeur:lambda s:s.lower()+s.lower()[::-1]
se transforme en
lambda s,l=[]:l.append(s.lower())or l[-1]+l[-1][::-1]
Nombre de caractères:
,l=[]
5 caractèresl.append()or
13 caractèresl[-1]
5 caractères pour chaque utilisationSeuil de rentabilité
La quantité de caractère ajouté est la suivante:
uses*(5-length) + 18 + length
Dans l'exemple précédent, l'instruction est
s.lower()
composée de 9 caractères et est utilisée 2 fois, en appliquant cette technique à 19 caractères. S'il était utilisé 7 fois, il y aurait une réduction d'un caractère.La quantité d'utilisations minimales de cette technique vaut la peine
min_uses = (18+length)/(length-5)
Upsides
list
objet si[0]
,.pop()
,[x:y]
et d' autres fonctions de la liste peut être utilisée pour les tricks. très situationnelInconvénients
5
Utilise un dictionnaire
thanks @Zgarb
Même idée que ci-dessus Déclarer un dictionnaire en tant que paramètre et utiliser
.setdefault()
pour stocker (et renvoyer) la valeur:lambda s:s.lower()+s.lower()[::-1]
se transforme en
lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]
Remarque: contrairement à la
list
contrepartie,setdefault
renvoie la valeur attribuée.Nombre de caractères:
,d={}
5 caractèresd.setdefault(k,)
16 caractèresd[k]
4 caractères pour chaque utilisationSeuil de rentabilité
La quantité de caractère ajouté est la suivante:
(uses-1)*(4-length) + 21
Dans l'exemple précédent, l'instruction est
s.lower()
composée de 9 caractères et est utilisée 2 fois, en appliquant cette technique à 16 caractères. S'il était utilisé 7 fois, il y aurait une réduction d'un caractère.La quantité d'utilisations minimales de cette technique vaut la peine
min_uses = 1-21/(4-length)
Upsides / Inconvénients
4
Autres considérations
lambda
pouvez probablement la supprimer et réécrire la fonction avecdef
/input
pour un programme plus court.la source
lambda s,d={}:d.setdefault(0,s.lower())+d[0][::-1]
il est également réutilisable.list.extend
pour ajouter plusieurs éléments à la fois, ce qui sera plus court quelist.append
plusieurs fois.Utilisez pour définir les variables et renvoyer les données après opération comme ceci:
la source
Liste des compréhensions
Il s’agit plus d’un dernier recours car c’est si peu d ’égoïste, mais vous pouvez faire
[<expression> for <variable> in <value>]
pour pseudo-définir une variable dans un lambda. Fondamentalement, le seul point positif de cette méthode est que l'expression interne peut rester lisible, ce qui est évidemment le moindre de vos soucis lorsque vous jouez au golf.
la source