Existe-t-il un one-liner pratique pour générer une liste de nombres et leurs homologues négatifs en Python?
Par exemple, disons que je veux générer une liste avec les nombres 6 à 9 et -6 à -9.
Mon approche actuelle est:
l = [x for x in range(6,10)]
l += [-x for x in l]
Un simple "one-liner" serait:
l = [x for x in range(6,10)] + [y for y in range(-9, -5)]
Cependant, générer deux listes, puis les réunir, semble peu pratique.
scalar or array-like, shape
irait bien.Réponses:
Je ne sais pas si la commande est importante, mais vous pouvez créer un tuple et le déballer dans une liste de compréhension.
la source
Créez une fonction agréable et lisible:
Usage:
C'est ainsi que vous obtenez une doublure pratique pour tout. Évitez d'essayer de ressembler à un pirate pro magique.
la source
y
àsignedValue
. Pour moi, la véritable valeur ajoutée de l'approche de définition d'une fonction serait de fournir des résultats dans l'ordre strict de la question posée (positive, puis négative) tout en évitant le problème de la ligne unique de Barmarchain
dans laquelle des arguments numériques légèrement différents ont à coder en dur deux fois.list
ou autre chose.) Après des années à essayer de codifier la meilleure façon de prendre ces décisions, le seul principe général qui a du sens pour moi : s'il y a un nom évident et bon à donner à quelque chose dans le programme, profitez-en pour le faire (et les fonctions sont l'une des façons dont nous le faisons).Je dirais que la solution la plus simple consiste à déballer deux plages dans une liste à l'aide de l'
*
opérateur de déballage:Non seulement c'est la réponse la plus courte proposée à ce jour, mais c'est aussi la plus performante, car elle ne construit qu'une seule liste et n'implique aucun appel de fonction au-delà des deux.
range
s.J'ai vérifié cela en testant toutes les réponses à cette question en utilisant le
timeit
module:(test de timeit effectué avec Python 3.6.9 sur mon propre ordinateur (spécifications moyennes))
la source
[*range(x, y), *range(-y + 1, -x + 1)]
Vous pouvez utiliser
itertools.chain()
pour concaténer les deux plages.la source
Vous pouvez utiliser
itertools.product
, qui est le produit cartésien.Cela peut être plus lent car vous utilisez la multiplication, mais devrait être facile à lire.
Si vous souhaitez une solution purement fonctionnelle, vous pouvez également importer
itertools.starmap
etoperator.mul
:Cependant, cela est moins lisible.
la source
product
,starmap
etopertaor.mul
inutilement obtuse par rapport aux compréhensions de listes imbriquées, mais j'approuve la suggestion d'utiliser la multiplication.[x * sign for sign in (1, -1) for x in range(6, 10)]
n'est que 10% plus lent que[y for x in range(6, 10) for y in (x, -x)]
, et dans les cas où l'ordre est important, plus de 3 fois plus rapide que le tri de l'approche basée sur les tuples.starmap
etmul
devrait être évité, mais je penseproduct
que cela le rend plus lisible, car il regroupe les itérateurs et leurs éléments séparément. Les boucles doubles dans la compréhension des listes peuvent également prêter à confusion, en raison de leur ordre inattendu.Vous êtes vraiment proche, avec la combinaison de deux
range
objets. Mais il existe un moyen plus simple de le faire:Autrement dit, convertissez chaque
range
objet en une liste, puis concaténez les deux listes.Une autre approche, en utilisant itertools:
itertools.chain()
c'est comme un généralisé+
: au lieu d'ajouter deux listes, il enchaîne un itérateur après l'autre pour en faire un "super-itérateur". Passez ensuite cela àlist()
et vous obtenez une liste concrète, avec tous les numéros que vous voulez en mémoire.la source
[x for x in ...]
est mieux orthographiéelist(...)
.Pesant avec encore une autre possibilité.
Si vous voulez la lisibilité, votre doublure d'origine était plutôt bonne, mais je changerais les plages pour qu'elles soient les mêmes car je pense que les limites négatives rendent les choses moins claires.
la source
L'OMI, l'approche utilisée
itertools.chain
dans quelques autres réponses est certainement la plus propre de celles fournies jusqu'à présent.Cependant, comme dans votre cas, l'ordre des valeurs n'a pas d'importance , vous pouvez éviter d'avoir à définir deux
range
objets explicites , et ainsi éviter de faire toutes les mathématiques off-by-one nécessaires à unerange
indexation négative , en utilisantitertools.chain.from_iterable
:Tad verbeux, mais assez lisible.
Une autre option similaire consiste à utiliser le décompactage tuple / argument avec plain
chain
:Plus concis, mais je trouve que le déballage des tuples est plus difficile à analyser dans un scan rapide.
la source
Ceci est une variation sur un thème (voir @Derte trdelník de réponse ) suivant la philosophie de
itertools
laquelleL'idée est que, pendant que nous définissons une nouvelle fonction, nous pouvons aussi bien la rendre générique:
et l'appliquer à un
range
itérateur particulier :la source
Si vous souhaitez conserver l'ordre que vous avez spécifié, vous pouvez utiliser le générateur de plage intégré de Python avec un conditionnel:
Ce qui vous donne la sortie:
Et fonctionne également avec 0 comme point de départ pour la gamme complète.
la source
start
.Il peut y avoir différentes façons de faire le travail.
Variables données: 1. début = 6 2. arrêt = 10
Vous pouvez également essayer ceci, pour différentes approches:
la source
Tout comme les symétries.
a = 6 b = 10
nums = [x + y pour x dans (- (a + b-1), 0) pour y dans la plage (a, b)]
Le résultat doit être -9, -8, ..., 8, 9.
Je crois que l'expression nums peut être améliorée, ce qui suit "in" et "range" me semble toujours déséquilibré.
la source