Gibt es einen praktischen Einzeiler, um eine Liste von Zahlen und ihren negativen Gegenstücken in Python zu erstellen?
Angenommen, ich möchte eine Liste mit den Nummern 6 bis 9 und -6 bis -9 erstellen.
Mein aktueller Ansatz ist:
l = [x for x in range(6,10)]
l += [-x for x in l]
Ein einfacher "Einzeiler" wäre:
l = [x for x in range(6,10)] + [y for y in range(-9, -5)]
Es erscheint jedoch unpraktisch, zwei Listen zu erstellen und diese dann zusammenzufügen.
python
python-3.x
upe
quelle
quelle
scalar or array-like, shape
wäre jede in Ordnung.Antworten:
Ich bin mir nicht sicher, ob die Reihenfolge wichtig ist, aber Sie können ein Tupel erstellen und es in einem Listenverständnis auspacken.
quelle
Erstellen Sie eine schöne und lesbare Funktion:
Verwendungszweck:
So erhalten Sie für alles einen praktischen Einzeiler. Vermeiden Sie es, wie ein magischer Profi-Hacker auszusehen.
quelle
y
zusignedValue
. Für mich wäre der wahre Mehrwert des Ansatzes zum Definieren einer Funktion, Ergebnisse in der strengen Reihenfolge zu liefern, in der die Frage gestellt wurde (positiv, dann negativ), während das Problem von Barmars Einzeiler vermieden wird,chain
in dem leicht unterschiedliche numerische Argumente vorliegen zweimal fest codiert sein.list
oder was auch immer übergeben wird.) Nach Jahren des Versuchs zu kodifizieren, wie diese Entscheidungen am besten getroffen werden können, ist dies das einzige allgemeine Prinzip, das für mich Sinn macht : Wenn es einen offensichtlichen, guten Namen für etwas im Programm gibt, nutzen Sie die Gelegenheit dazu (und Funktionen sind eine der Möglichkeiten, wie wir dies tun).Ich würde sagen, die einfachste Lösung besteht darin, zwei Bereiche mit dem
*
Entpackungsoperator in eine Liste zu entpacken :Dies ist nicht nur die kürzeste vorgeschlagene Antwort, sondern auch die performanteste, da nur eine einzige Liste erstellt wird und keine Funktionsaufrufe über die beiden hinausgehen
range
.Ich habe dies überprüft, indem ich alle Antworten dieser Frage mit dem
timeit
Modul getestet habe :(Timeit-Tests mit Python 3.6.9 auf meinem eigenen Computer durchgeführt (durchschnittliche Spezifikationen))
quelle
[*range(x, y), *range(-y + 1, -x + 1)]
Sie können
itertools.chain()
die beiden Bereiche verketten.quelle
Sie können verwenden
itertools.product
, welches das kartesische Produkt ist.Dies ist möglicherweise langsamer, da Sie die Multiplikation verwenden, sollte jedoch leicht zu lesen sein.
Wenn Sie eine rein funktionale Lösung wünschen, können Sie auch importieren
itertools.starmap
undoperator.mul
:Dies ist jedoch weniger lesbar.
quelle
product
,starmap
undopertaor.mul
unnötig stumpf im Vergleich zu verschachtelter Liste Comprehensions, aber ich befürworte den Vorschlag der Multiplikation mit.[x * sign for sign in (1, -1) for x in range(6, 10)]
ist nur 10% langsamer als[y for x in range(6, 10) for y in (x, -x)]
und in Fällen, in denen die Reihenfolge wichtig ist, mehr als dreimal schneller als das Sortieren des tupelbasierten Ansatzes.starmap
undmul
sollte vermieden werden, aber ich denke, esproduct
macht es besser lesbar, da es die Iteratoren und ihre Elemente getrennt gruppiert. Doppelschleifen im Listenverständnis können aufgrund ihrer unerwarteten Reihenfolge ebenfalls verwirrend sein.Sie sind wirklich nah dran, wenn Sie zwei
range
Objekte kombinieren . Aber es gibt einen einfacheren Weg:Konvertieren Sie also jedes
range
Objekt in eine Liste und verketten Sie dann die beiden Listen.Ein anderer Ansatz, der itertools verwendet:
itertools.chain()
ist wie eine Verallgemeinerung+
: Anstatt zwei Listen hinzuzufügen, verkettet es einen Iterator nach dem anderen, um einen "Superiterator" zu erstellen. Übergeben Sie das dann anlist()
und Sie erhalten eine konkrete Liste mit allen gewünschten Zahlen im Speicher.quelle
[x for x in ...]
die besser geschrieben istlist(...)
.Mit einer weiteren Möglichkeit abwägen.
Wenn Sie Lesbarkeit wünschen, war Ihr ursprünglicher Einzeiler ziemlich gut, aber ich würde die Bereiche so ändern, dass sie der Meinung sind, dass die negativen Grenzen die Dinge weniger klar machen.
quelle
IMO ist der Ansatz,
itertools.chain
der in einigen anderen Antworten vorgestellt wird, definitiv der sauberste unter den bisher angebotenen.Da in Ihrem Fall jedoch die Reihenfolge der Werte keine Rolle spielt , können Sie vermeiden, zwei explizite
range
Objekte definieren zu müssen , und somit vermeiden, die für die negativerange
Indizierung erforderliche Off-by-One-Mathematik durchzuführen, indem Sie Folgendes verwendenitertools.chain.from_iterable
:Tad ausführlich, aber lesbar genug.
Eine andere ähnliche Option ist das Entpacken von Tupeln / Argumenten mit plain
chain
:Prägnanter, aber ich finde es schwieriger, Tupel auszupacken, um einen schnellen Scan durchzuführen.
quelle
Dies ist eine Variation über ein Thema (siehe @Derte Trdelnik ‚s Antwort ) im Anschluss an die Philosophie von
itertools
woDie Idee ist, dass wir, während wir eine neue Funktion definieren, sie genauso gut generisch machen können:
und wenden Sie es auf einen bestimmten
range
Iterator an:quelle
Wenn Sie die von Ihnen angegebene Reihenfolge beibehalten möchten, können Sie den in Python integrierten Bereichsgenerator mit einer Bedingung verwenden:
Welches gibt Ihnen die Ausgabe:
Und funktioniert auch mit 0 als Start für den gesamten Bereich.
quelle
start
.Es gibt verschiedene Möglichkeiten, die Arbeit zu erledigen.
Angegebene Variablen: 1. Start = 6 2. Stopp = 10
Sie können dies auch für verschiedene Ansätze versuchen:
quelle
Ich mag Symmetrien.
a = 6 b = 10
nums = [x + y für x in (- (a + b-1), 0) für y im Bereich (a, b)]
Das Ergebnis sollte -9, -8, ..., 8, 9 sein.
Ich glaube, dass der nums-Ausdruck verbessert werden kann. Was auf "in" und "range" folgt, erscheint mir immer noch unausgeglichen.
quelle