Eine map () erhalten, um eine Liste in Python 3.x zurückzugeben

523

Ich versuche, eine Liste hexadezimal zuzuordnen und die Liste dann an anderer Stelle zu verwenden. In Python 2.6 war dies einfach:

A: Python 2.6:

>>> map(chr, [66, 53, 0, 94])
['B', '5', '\x00', '^']

In Python 3.1 gibt das Obige jedoch ein Kartenobjekt zurück.

B: Python 3.1:

>>> map(chr, [66, 53, 0, 94])
<map object at 0x00AF5570>

Wie rufe ich die zugeordnete Liste (wie in A oben) unter Python 3.x ab?

Gibt es alternativ einen besseren Weg, dies zu tun? Mein anfängliches Listenobjekt enthält ungefähr 45 Elemente und die ID möchte sie in hexadezimal konvertieren.

Mozami
quelle
2
Es ist pythonischer, ein Listenverständnis zu verwenden . map()wurde fast aus der Sprache entfernt, weil es keinen Grund gibt, sie über ein Listenverständnis oder eine forSchleife zu verwenden.
Boris

Antworten:

771

Mach das:

list(map(chr,[66,53,0,94]))

In Python 3+ geben viele Prozesse, die über Iterables iterieren, Iteratoren selbst zurück. In den meisten Fällen wird dadurch Speicherplatz gespart, und die Dinge sollten schneller laufen.

Wenn Sie diese Liste nur noch durchlaufen möchten, müssen Sie sie nicht einmal in eine Liste konvertieren, da Sie das mapObjekt dennoch wie folgt durchlaufen können :

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)
Triptychon
quelle
15
Natürlich können Sie auch darüber iterieren: (chr (x) für x in [65,66,67,68]). Es braucht nicht einmal eine Karte.
Hughdbrown
2
@hughdbrown Das Argument für die Verwendung von 3.1 mapwäre eine verzögerte Auswertung, wenn eine komplexe Funktion, große Datenmengen oder Streams durchlaufen werden .
Andrew Keeton
18
@ Andrew tatsächlich Hugh verwendet ein Generator-Verständnis, das das gleiche tun würde. Beachten Sie die Klammern und nicht die eckigen Klammern.
Triptychon
5
Mögliche Lösung (schneller für große Eingänge zu) , wenn die Werte bekannt sind ASCII / Latin-1 ist bulk Umwandlungen an der C - Schicht zu tun: bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')die eine macht strdurch die Vermeidung von für jedes Element für eine Bulk - Konvertierung Funktionsaufrufe Python schneller von Alle Elemente, die nur Funktionsaufrufe der Ebene C verwenden. Sie können das Obige einschließen, listwenn Sie wirklich eines listder einzelnen Zeichen benötigen. Da stres sich jedoch bereits um eine Iteration seiner eigenen Zeichen handelt, ist der einzige Grund, warum Sie dies tun würden, wenn Sie eine Veränderbarkeit benötigen.
ShadowRanger
1
list (map (str, [1,2,3])) gibt "Fehler im Argument" für Python 3.4.3 unter CentOS 7. Das Listenverständnis funktioniert.
Andor
108

Neu und ordentlich in Python 3.5:

[*map(chr, [66, 53, 0, 94])]

Dank zusätzlicher Verpackungsverallgemeinerungen

AKTUALISIEREN

Immer auf der Suche nach kürzeren Wegen, entdeckte ich, dass dieser auch funktioniert:

*map(chr, [66, 53, 0, 94]),

Das Auspacken funktioniert auch in Tupeln. Beachten Sie das Komma am Ende. Dies macht es zu einem Tupel von 1 Element. Das heißt, es ist gleichbedeutend mit(*map(chr, [66, 53, 0, 94]),)

Es ist nur um ein Zeichen kürzer als die Version mit den Listenklammern, aber meiner Meinung nach ist es besser zu schreiben, weil Sie direkt mit dem Sternchen beginnen - der Erweiterungssyntax, also denke ich, dass es im Kopf weicher ist. :) :)

Israel Unterman
quelle
11
@Quelklef list()sieht nicht so ordentlich aus
Arijoon
5
@Quelklef: Außerdem ist das Auspacken trivial schneller, da der listKonstruktor nicht nachgeschlagen und allgemeine Funktionsaufrufmaschinen aufgerufen werden müssen. Für eine lange Eingabe spielt es keine Rolle; Für einen kurzen Fall kann es einen großen Unterschied machen. Wenn Sie den obigen Code mit der Eingabe als verwenden, tupledamit diese nicht wiederholt rekonstruiert wird, ipythonzeigen Mikrobenchmarks, dass der list()Wrapping-Ansatz etwa 20% länger dauert als das Entpacken. In absoluten Zahlen sprechen wir von 150 ns, was trivial ist, aber Sie haben die Idee.
ShadowRanger
Was war los mit dem alten map? Vielleicht mit einem neuen Namen ( lmap?), Wenn der neue Standard darin besteht, einen Iterator zurückzugeben?
Giorgio
1
*map()gibt Syntaxfehler an Python 3.6: can't use starred expression here. Sie müssen es in ein setzen list:[ *map() ]
ALH
4
@ALH Sie haben das Komma am Ende des Befehls verpasst. Einfacher Fehler zu machen!
LondonRob
103

Warum machst du das nicht:

[chr(x) for x in [66,53,0,94]]

Es heißt Listenverständnis. Sie finden viele Informationen bei Google, aber hier ist der Link zur Python (2.6) -Dokumentation zum Listenverständnis . Die Python 3-Dokumentation könnte Sie jedoch mehr interessieren .

Mark Rushakoff
quelle
4
Hmmmm. Möglicherweise muss es eine allgemeine Veröffentlichung zu Listenverständnissen, Generatoren, map (), zip () und vielen anderen schnellen Iterationsgütern in Python geben.
Hughdbrown
46
Ich denke, weil es ausführlicher ist, müssen Sie eine zusätzliche Variable (zweimal) schreiben ... Wenn die Operation komplexer ist und Sie am Ende ein Lambda schreiben oder Sie auch einige Elemente fallen lassen müssen, denke ich, dass ein Verständnis definitiv besser ist als eine Karte + Filter, aber wenn Sie bereits die Funktion haben, die Sie anwenden möchten, ist die Karte prägnanter.
Fortan
1
+1: Einfacher zu lesen und ermöglicht es Ihnen, Funktionen mit vielen Parametern zu verwenden
Le Droid
7
map(chr, [66,53,0,94])ist definitiv prägnanter als [chr(x) for x in [66,53,0,94]].
Giorgio
viel schneller als die anderen Antworten
Evhz
25

Die Listenrückgabe-Kartenfunktion hat den Vorteil, dass die Eingabe gespeichert wird, insbesondere während interaktiver Sitzungen. Sie können eine lmapFunktion definieren (in Analogie zu Python2 imap), die eine Liste zurückgibt:

lmap = lambda func, *iterable: list(map(func, *iterable))

Dann erledigt das Anrufen lmapanstelle von mapden Job: lmap(str, x)ist um 5 Zeichen kürzer (in diesem Fall 30%) als list(map(str, x))und sicherlich kürzer als [str(v) for v in x]. Sie können ähnliche Funktionen auch für erstellen filter.

Es gab einen Kommentar zur ursprünglichen Frage:

Ich würde eine Umbenennung in Getting map () vorschlagen, um eine Liste in Python 3 zurückzugeben. * Dies gilt für alle Python3-Versionen. Gibt es eine Möglichkeit, dies zu tun? - Meawoppl 24. Januar um 17:58 Uhr

Das ist möglich, aber es ist eine sehr schlechte Idee. Nur zum Spaß, hier ist, wie Sie es tun können ( aber nicht sollten ):

__global_map = map #keep reference to the original map
lmap = lambda func, *iterable: list(__global_map(func, *iterable)) # using "map" here will cause infinite recursion
map = lmap
x = [1, 2, 3]
map(str, x) #test
map = __global_map #restore the original map and don't do that again
map(str, x) #iterator
Boris Gorelik
quelle
4

Konvertieren meines alten Kommentars für eine bessere Sichtbarkeit: Für einen "besseren Weg, dies zu tun" ohne mapvollständig, wenn Ihre Eingaben als ASCII-Ordnungszahlen bekannt sind, ist es im Allgemeinen viel schneller bytes, a la zu konvertieren und zu dekodieren bytes(list_of_ordinals).decode('ascii'). Das bringt Ihnen einen strder Werte, aber wenn Sie einen listfür Veränderlichkeit oder ähnliches benötigen , können Sie ihn einfach konvertieren (und er ist immer noch schneller). Zum Beispiel in ipythonMikrobenchmarks, die 45 Eingänge konvertieren:

>>> %%timeit -r5 ordinals = list(range(45))
... list(map(chr, ordinals))
...
3.91 µs ± 60.2 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*map(chr, ordinals)]
...
3.84 µs ± 219 ns per loop (mean ± std. dev. of 5 runs, 100000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... [*bytes(ordinals).decode('ascii')]
...
1.43 µs ± 49.7 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

>>> %%timeit -r5 ordinals = list(range(45))
... bytes(ordinals).decode('ascii')
...
781 ns ± 15.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)

Wenn Sie es als belassen str, dauert es ~ 20% der Zeit der schnellsten mapLösungen; Selbst wenn Sie zurück zur Liste konvertieren, sind es immer noch weniger als 40% der schnellsten mapLösung. Die Massenkonvertierung über bytesund bytes.decodedann die Massenkonvertierung zurück in listspart viel Arbeit, funktioniert jedoch, wie bereits erwähnt, nur, wenn alle Ihre Eingaben ASCII-Ordnungszahlen sind (oder Ordnungszahlen in einem Gebietsschema für ein Byte pro Zeichen, z latin-1. B. spezifische Codierung ).

ShadowRanger
quelle
2
list(map(chr, [66, 53, 0, 94]))

map (func, * iterables) -> map object Erstellt einen Iterator, der die Funktion mithilfe von Argumenten aus jeder der iterables berechnet. Stoppt, wenn der kürzeste iterable erschöpft ist.

"Machen Sie einen Iterator"

bedeutet, dass ein Iterator zurückgegeben wird.

"das berechnet die Funktion unter Verwendung von Argumenten aus jeder der iterablen"

bedeutet, dass die next () -Funktion des Iterators einen Wert jeder Iterable nimmt und jede von ihnen an einen Positionsparameter der Funktion übergibt.

Sie erhalten also einen Iterator von der Funktion map () und übergeben ihn einfach an die integrierte Funktion list () oder verwenden Listenverständnisse.

Ini
quelle
2

Zusätzlich zu den obigen Antworten in Python 3können wir einfach einen listder Ergebniswerte aus einem mapas erstellen

li = []
for x in map(chr,[66,53,0,94]):
    li.append(x)

print (li)
>>>['B', '5', '\x00', '^']

Wir können durch ein anderes Beispiel verallgemeinern, in dem ich getroffen wurde. Operationen auf der Karte können auch auf ähnliche Weise wie im regexProblem behandelt werden. Wir können eine Funktion schreiben, um listElemente auf die Karte zu erhalten und gleichzeitig die Ergebnismenge zu erhalten . Ex.

b = 'Strings: 1,072, Another String: 474 '
li = []
for x in map(int,map(int, re.findall('\d+', b))):
    li.append(x)

print (li)
>>>[1, 72, 474]
Harry_pb
quelle
@miradulo Ich nahm an, dass in Python 2 eine Liste zurückgegeben wurde, aber in Python 3 wird nur der Typ zurückgegeben und ich habe nur versucht, im gleichen Format zu geben. Wenn Sie denken, dass es unnötig ist, gibt es vielleicht Leute wie mich, die es nützlich finden können, und deshalb habe ich hinzugefügt.
Harry_pb
2
Wenn es bereits ein Listenverständnis, eine Listenfunktion und eine Entpackungsantwort gibt, fügt eine explizite for-Schleife meiner Meinung nach nicht viel hinzu.
Miradulo
1

Sie können versuchen, eine Liste aus dem Kartenobjekt abzurufen, indem Sie einfach jedes Element im Objekt iterieren und in einer anderen Variablen speichern.

a = map(chr, [66, 53, 0, 94])
b = [item for item in a]
print(b)
>>>['B', '5', '\x00', '^']
Akshay Satpaise
quelle
0

Mit dem Listenverständnis in Python und dem grundlegenden Dienstprogramm für Kartenfunktionen können Sie dies auch tun:

chi = [x for x in map(chr,[66,53,0,94])]

darshan ks
quelle
Die Chi-Liste enthält den ASIC-Wert der angegebenen Elemente.
Darshan ks