2016-04-08 12 views
1

("dezip" ist offensichtlich ein schlechter Name, aber ich bin mir nicht sicher, was der richtige wäre. Bitte entschuldigen Sie, wenn ich eine autoritative Antwort verpasst habe, weil ich nicht weiß was suchen)most pythonon3 dezip (?) Implementation

Lasst uns sagen, dass wir

people = [ 
    (1, 'anne'), 
    (2, 'ben'), 
    (3, 'charlie'), 
] 

(gemeinsam in django für Wahlen etc.)

Jetzt wollen wir eine Liste der „Schlüssel“ oder eine Liste der ersten Elemente haben. [1, 2, 3]

In Python 3 Ich verwende

people_ids, _ = list(zip(*people)) 
# or even 
people_ids = [p[0] for p in people] 

Der Zip Weg scheint nicht sehr sauber, vor allem mit den zusätzlichen list(...) von Python 3 Herstellung erforderlich zip einen Iterator.

Der zweite Verständnisansatz ist etwas besser lesbar, würde aber auch nicht verallgemeinern, z. Rückhollisten der zweiten, dritten Elemente usw. im selben Aufruf.

Gibt es einen besseren Weg?

(wobei „besser“ bedeutet vor allem sauber und gut lesbar, aber die Leistung könnte auch einige erhebliche)

+0

_Der zweite Verständnisansatz ist etwas besser lesbar, würde aber nicht verallgemeinern, z. Rücksende-Listen der zweiten, dritten Elemente etc._ warum wird es nicht? Übergeben Sie eine einzelne Zahl, es wird ein einzelnes Element zurückgegeben. Übergeben Sie es an ein Scheibenobjekt, es wird ein Stück der ursprünglichen Scheibenliste zurückgegeben. Es sieht nach einer netten und sauberen Lösung aus. –

+0

Lassen Sie uns sagen, wir wollen 'people_ids, people_names = [???]' kann nicht in einem lesbaren Verständnis AFAIK getan werden. Aber vielleicht hast du recht, wenn du nur einen Satz von Elementen willst, sei klar und schreibe das Verständnis auf. – SColvin

+0

aktualisiert, um zu verdeutlichen, was ich unter "zweite, dritte Elemente" verstehe – SColvin

Antwort

2

Mit next, können Sie das erste Element aus der iterable erhalten:

>>> people = [ 
...  (1, 'anne'), 
...  (2, 'ben'), 
...  (3, 'charlie'), 
... ] 
>>> next(zip(*people)) 
(1, 2, 3) 

Alternative mit map mit operator.itemgetter:

>>> import operator 
>>> list(map(operator.itemgetter(0), people)) 
[1, 2, 3] 

BTW

, zip Lösung ohne list sollte funktionieren:

>>> people_ids, _ = zip(*people) 
>>> people_ids 
(1, 2, 3) 
+1

Entschuldigung, was Sie nicht tun können, ist 'people_ids = zip (* people) [0]'. Sie haben einen Tippfehler, ich denke, Sie meinen mit ** out ** – SColvin

+0

Ich denke, die wirkliche Antwort auf meine Frage ist ** NEIN **. Aber das ist wahrscheinlich einer Antwort am nächsten. – SColvin

+0

@SColvin, danke für das Aufzeigen. Ich habe das Wort festgelegt. – falsetru

0

Für das spezielle Beispiel können Sie "Missbrauch" ein wenig die dict:

people = [ 
    (1, 'anne'), 
    (2, 'ben'), 
    (3, 'charlie'), 
] 

d_people = dict(people) 

Und dann haben Sie einen schönen Datenmodell. Dies hat einige Probleme: Schlüssel können nicht wiederholt werden und funktionieren nicht mit Tupeln mit mehr als zwei Elementen. Aber für diesen Fall (was ziemlich typisch ist!) Funktioniert das sehr gut.

Dann können Sie einfach die Schlüssel von keys tun:

d_people.keys() 

oder explizite Liste, entweder:

list(d_people) 
list(d_people.keys()) 

, die gleichwertig sind.

0

Eine Untergruppe basierend auf IDs erhalten Sie unter operator.itemgetter. Das Abrufen eines Unterfensters von gezippten Werten kann durch Erstellen eines expliziten Abschnittsobjekts und Übergeben an die Funktion erfolgen.

import operator 

people = [ 
    (1, 'anne', 'some'), 
    (2, 'ben', 'another'), 
    (3, 'charlie', 'field'), 
] 

people_ids = [p[0] for p in people] # 0 may be passed as funtion argument 
people_ids_and_another = [operator.itemgetter(*[0, 2])(p) for p in people] # [0, 2] may be passed as function argument 
people_ids_and_name_via_slice = [p[slice(0,2,None)] for p in people] # equal to p[0:2], but passable as argument 

Funktionsnutzung Um zu demonstrieren:

def dezip(seq, what): 
    if isinstance(what, list): 
     return [operator.itemgetter(*what)(p) for p in people] 
    else: 
     return [p[what] for p in people] 

assert dezip(people, slice(0,2,None)) == [(1, 'anne'), (2, 'ben'), (3, 'charlie')] 
assert dezip(people, 0) == [1, 2, 3] 
assert dezip(people, [0, 2]) == [(1, 'some'), (2, 'another'), (3, 'field')] 

Wenn Sie "Liste der Indizes Anforderung fallen werden, können Sie if-Anweisung in der Funktion Körper fallen.