l = ["a", "b", "c", "d", "e"]
Ich möchte diese Liste in ein Wörterbuch wie das folgende konvertieren:
d = {"a": "b", "c": "d", "e": ""}
Im Grunde genommen sind die Abschlüsse also Schlüssel, während die Gewinnchancen Werte sind. Ich weiß, dass ich es auf eine "nicht-pythonische" Weise tun kann, wie zum Beispiel eine for-Schleife mit if-Anweisungen, aber ich glaube, dass es eine "pythonischere" Weise geben sollte, um dies zu erreichen. Also, ich freue mich über jede Hilfe :)
Mit dem üblichen Grouper-Rezept können Sie Folgendes tun:
Python 2:
d = dict(itertools.izip_longest(*[iter(l)] * 2, fillvalue=""))
Python 3:
d = dict(itertools.Zip_longest(*[iter(l)] * 2, fillvalue=""))
Wenn Sie immer noch darüber nachdenken, was die! Du wärst nicht alleine, es ist eigentlich gar nicht so kompliziert, lass es mich erklären.
Wir wollen die folgende Liste in ein Wörterbuch umwandeln, indem wir die ungeraden Einträge (von 1 an gezählt) als Tasten verwenden, die ihren aufeinanderfolgenden geraden Einträgen zugeordnet sind.
l = ["a", "b", "c", "d", "e"]
Um ein Wörterbuch zu erstellen, können wir die eingebaute Funktion dict
für Zuordnungstypen verwenden. Gemäß Handbuch werden die folgenden Methoden unterstützt.
dict(one=1, two=2)
dict({'one': 1, 'two': 2})
dict(Zip(('one', 'two'), (1, 2)))
dict([['two', 2], ['one', 1]])
Die letzte Option schlägt vor, dass wir eine Liste von Listen mit 2 Werten oder (key, value)
Tupel, also wollen wir unsere sequentielle Liste in:
l = [["a", "b"], ["c", "d"], ["e",]]
Wir werden auch in die Funktion Zip
eingeführt, eine der eingebauten Funktionen , die im Handbuch erklärt wird:
gibt eine Liste von Tupeln zurück, wobei das i-te Tupel das i-te Element aus jedem der Argumente enthält
Mit anderen Worten, wenn wir unsere Liste in zwei Listen umwandeln können, a, c, e
und b, d
dann Zip
erledigt den Rest.
Slicings , das wir zusammen mit Strings und weiter unten im Abschnitt List sehen, in dem hauptsächlich der Bereich verwendet wird oder kurze Scheibe Notation, aber das ist, was die lange Scheibe Notation sieht aus wie und was wir mit Schritt erreichen können:
>>> l[::2]
['a', 'c', 'e']
>>> l[1::2]
['b', 'd']
>>> Zip(['a', 'c', 'e'], ['b', 'd'])
[('a', 'b'), ('c', 'd')]
>>> dict(Zip(l[::2], l[1::2]))
{'a': 'b', 'c': 'd'}
Obwohl dies der einfachste Weg ist, die beteiligten Mechanismen zu verstehen, gibt es einen Nachteil, da Slices jedes Mal neue Listenobjekte sind, wie in diesem Klonbeispiel zu sehen ist:
>>> a = [1, 2, 3]
>>> b = a
>>> b
[1, 2, 3]
>>> b is a
True
>>> b = a[:]
>>> b
[1, 2, 3]
>>> b is a
False
Auch wenn b wie a aussieht, handelt es sich jetzt um zwei separate Objekte, weshalb wir lieber das Grouper-Rezept verwenden.
Obwohl der Grouper als Teil des itertools-Moduls erklärt wird, funktioniert er auch mit den Grundfunktionen einwandfrei.
Etwas ernstes Voodoo, oder? =) Aber eigentlich nichts anderes als ein bisschen Syntaxzucker für die Würze, das Zackenbarschrezept wird durch den folgenden Ausdruck erreicht.
*[iter(l)]*2
Was mehr oder weniger zu zwei Argumenten desselben Iterators in einer Liste führt, wenn das Sinn macht. Lassen Sie es uns aufschlüsseln, um Licht ins Dunkel zu bringen.
>>> l*2
['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e']
>>> [l]*2
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
>>> [iter(l)]*2
[<listiterator object at 0x100486450>, <listiterator object at 0x100486450>]
>>> Zip([iter(l)]*2)
[(<listiterator object at 0x1004865d0>,),(<listiterator object at 0x1004865d0>,)]
>>> Zip(*[iter(l)]*2)
[('a', 'b'), ('c', 'd')]
>>> dict(Zip(*[iter(l)]*2))
{'a': 'b', 'c': 'd'}
Wie Sie sehen, bleiben die Adressen für die beiden Iteratoren gleich. Wir arbeiten also mit demselben Iterator, von dem Zip zuerst einen Schlüssel erhält und dann jedes Mal einen Wert und einen Schlüssel und einen Wert, wenn Sie denselben Iterator betätigen, um das zu erreichen, was wir getan haben mit den Scheiben viel produktiver.
Sie würden sehr viel dasselbe mit dem Folgenden erreichen, das einen kleineren Was der? Faktor vielleicht trägt.
>>> it = iter(l)
>>> dict(Zip(it, it))
{'a': 'b', 'c': 'd'}
Was ist mit dem leeren Schlüssel e
, wenn Sie bemerkt haben, dass er in allen Beispielen fehlt, weil Zip
das kürzeste der beiden Argumente auswählt, also was sollen wir tun?.
Nun, eine Lösung könnte darin bestehen, Listen mit ungerader Länge einen leeren Wert hinzuzufügen. Sie können auch append
und eine if
-Anweisung verwenden, die den Trick ausführen würde, wenn auch etwas langweilig, oder?
>>> if len(l) % 2:
... l.append("")
>>> l
['a', 'b', 'c', 'd', 'e', '']
>>> dict(Zip(*[iter(l)]*2))
{'a': 'b', 'c': 'd', 'e': ''}
Nun, bevor Sie die Achseln zucken, um zu gehen, tippen Sie from itertools import izip_longest
Sie werden überrascht sein, dass dies nicht erforderlich ist. Wir können das Gleiche, noch besser, meiner Meinung nach mit den eingebauten Funktionen allein erreichen.
Ich bevorzuge die Verwendung der map () -Funktion anstelle von izip_longest () , die nicht nur eine kürzere Syntax verwendet, sondern auch einen Import erfordert, sondern eine tatsächliche None
Leerwert bei Bedarf, automatisch.
>>> l = ["a", "b", "c", "d", "e"]
>>> l
['a', 'b', 'c', 'd', 'e']
>>> dict(map(None, *[iter(l)]*2))
{'a': 'b', 'c': 'd', 'e': None}
Vergleicht man die Leistung der beiden Methoden, wie von KursedMetal hervorgehoben, so ist klar, dass das itertools-Modul die Kartenfunktion bei großen Volumina bei weitem übertrifft, wie ein Benchmark gegenüber 10 Millionen Datensätzen zeigt.
$ time python -c 'dict(map(None, *[iter(range(10000000))]*2))'
real 0m3.755s
user 0m2.815s
sys 0m0.869s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(10000000))]*2, fillvalue=None))'
real 0m2.102s
user 0m1.451s
sys 0m0.539s
Die Kosten für den Import des Moduls gehen jedoch zu Lasten kleinerer Datensätze, bei denen die Karte viel schneller bis zu 100.000 Datensätze zurückgibt, wenn sie von Kopf zu Kopf kommen.
$ time python -c 'dict(map(None, *[iter(range(100))]*2))'
real 0m0.046s
user 0m0.029s
sys 0m0.015s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100))]*2, fillvalue=None))'
real 0m0.067s
user 0m0.042s
sys 0m0.021s
$ time python -c 'dict(map(None, *[iter(range(100000))]*2))'
real 0m0.074s
user 0m0.050s
sys 0m0.022s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100000))]*2, fillvalue=None))'
real 0m0.075s
user 0m0.047s
sys 0m0.024s
Sehen Sie nichts dazu! =)
nJoy!
Ich würde für Rekursionen gehen:
l = ['a', 'b', 'c', 'd', 'e', ' ']
d = dict([(k, v) for k,v in Zip (l[::2], l[1::2])])
Ich bin mir nicht sicher, ob es dir helfen würde oder nicht, aber es funktioniert für mich:
l = ["a", "b", "c", "d", "e"]
outRes = dict((l[i], l[i+1]) if i+1 < len(l) else (l[i], '') for i in xrange(len(l)))