Grundlegendes zur Kartenfunktion

311
map(function, iterable, ...)

Wenden Sie die Funktion auf jedes iterierbare Element an und geben Sie eine Liste der Ergebnisse zurück. Wenn zusätzliche iterierbare Argumente übergeben werden, muss die Funktion so viele Argumente annehmen und wird parallel auf die Elemente aller iterierbaren Argumente angewendet.

Wenn eine Iterable kürzer als eine andere ist, wird angenommen, dass sie um Keine Elemente erweitert wird.

Wenn Funktion ist None, wird die Identitätsfunktion angenommen; Wenn mehrere Argumente vorhanden sind, wird map()eine Liste zurückgegeben, die aus Tupeln besteht, die die entsprechenden Elemente aus allen iterablen Elementen enthalten (eine Art Transponierungsoperation).

Die iterierbaren Argumente können eine Sequenz oder ein beliebiges iterierbares Objekt sein. Das Ergebnis ist immer eine Liste.

Welche Rolle spielt dies bei der Herstellung eines kartesischen Produkts?

content = map(tuple, array)

Welchen Effekt hat es, irgendwo ein Tupel zu platzieren? Mir ist auch aufgefallen, dass die Ausgabe ohne die Kartenfunktion ist abcund damit auch a, b, c.

Ich möchte diese Funktion vollständig verstehen. Die Referenzdefinitionen sind ebenfalls schwer zu verstehen. Zu viel ausgefallener Flaum.

Web Master
quelle
2
Was möchten Sie eigentlich erreichen und warum möchten Sie konkret verwenden map?
Kris Harper
3
@WebMaster Ja, gemäß dem ersten Satz in der Dokumentation, den Sie eingefügt haben - "Funktion auf jedes iterierbare Element anwenden". Der Rest des Absatzes befasst sich mit komplexeren Fällen - wie map(None, a, b, c)sich herausstellt zip(a, b, c). In der Praxis sieht man das jedoch sehr selten, gerade weil der zipAnruf gleichwertig ist.
lvc
9
Ich bemühe mich sehr, Python zu lernen und wann immer ich eine Definition in python.org öffne. Nach dem ersten Satz verstehe ich nichts. In Ordung. Danke.
Web Master
2
tupleist eine Funktion (nun, sie ist nuancierter als diese, aber sie verhält sich wie eine Funktion), die eine Iterierbarkeit annimmt und Ihnen ein Tupel mit denselben Elementen gibt - tuple([1, 2, 3])entspricht also (1, 2, 3). Denn map(tuple, array), arraywäre ein iterable von Iterables (eine Liste von Listen denken), und es gibt Ihnen jede innere Liste in ein Tupel zurückgedreht.
lvc
1
Im Allgemeinen ist es der erste Satz der Dokumentation einer Funktion, der am wichtigsten ist. Wenn Sie das verstehen, bekommen Sie den Kern davon. Der Rest davon gibt das Verhalten im Detail, und einiges davon wird ein bisschen undurchsichtig sein , mit zu beginnen, und Sie können über ein ungeradees Idiom basierte darauf kommen müssen , bevor Sie sehen : „Oh, das ist , was das bedeutet!“. Aber sobald Sie diesen Moment der Glühbirne für ein paar Einbauten haben, sollten Sie in der Lage sein, die Dokumente ein bisschen leichter zu verstehen.
lvc

Antworten:

441

mapist nicht besonders pythonisch. Ich würde stattdessen empfehlen, Listenverständnisse zu verwenden:

map(f, iterable)

ist im Grunde gleichbedeutend mit:

[f(x) for x in iterable]

mapEin kartesisches Produkt allein kann nicht hergestellt werden, da die Länge der Ausgabeliste immer der Länge der Eingabeliste entspricht. Sie können ein kartesisches Produkt mit einem Listenverständnis trivial ausführen:

[(a, b) for a in iterable_a for b in iterable_b]

Die Syntax ist etwas verwirrend - das entspricht im Grunde:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))
Dave
quelle
36
Ich finde es mapviel weniger ausführlich als Listenverständnisse, zumindest für den Fall, den Sie demonstrieren.
Marbel
1
Wie verwende ich eine Karte für Eigenschaften? Was ist das mapÄquivalent von [v.__name__ for v in (object, str)]?
A Sz
@ASz Wie wäre es map(lambda v: v.__name__, list)?
Kilian
10
Map ist schneller, da es keine Funktionen basierend auf der Länge der Iteratoren aufruft. Das Aufrufen von Funktionen hat Overhead. Sehen Sie 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati
1
@anati Ich dachte , mapwar manchmal schneller als Comprehensions, manchmal nicht, gerade wegen des Funktionsaufruf Overhead? Die Heuristik, die ich gelernt habe, ist insbesondere, dass das mapVerständnis schneller ist, wenn Sie einen zusätzlichen Funktionsaufruf einführen müssen. ZB wurde ich zu der Überzeugung gebracht, dass dies map(lambda foo: foo.bar, my_list)langsamer als foo.bar for foo in my_listund sogar map(operator.add, my_list_of_pairs)langsamer als x + y for x, y in my_list_of_pairsgenau wegen des zusätzlichen Funktionsaufrufs ist.
mtraceur
86

mapbezieht sich überhaupt nicht auf ein kartesisches Produkt, obwohl ich mir vorstelle, dass jemand, der sich mit funktionaler Programmierung auskennt, einen unmöglich zu verstehenden Weg finden könnte, ein Produkt mit zu erzeugen map.

map in Python 3 entspricht dem:

def map(func, iterable):
    for i in iterable:
        yield func(i)

und der einzige Unterschied in Python 2 besteht darin, dass eine vollständige Liste der Ergebnisse erstellt wird, die alle auf einmal zurückgeben, anstatt yielding.

Obwohl die Python-Konvention normalerweise Listenverständnisse (oder Generatorausdrücke) bevorzugt, um das gleiche Ergebnis wie bei einem Aufruf zu erzielen map, insbesondere wenn Sie einen Lambda-Ausdruck als erstes Argument verwenden:

[func(i) for i in iterable]

Als Beispiel für das, was Sie in den Kommentaren zu der Frage "Verwandle einen String in ein Array" gefragt haben, möchten Sie mit "Array" wahrscheinlich entweder ein Tupel oder eine Liste (beide verhalten sich ein wenig wie Arrays aus anderen Sprachen). - -

 >>> a = "hello, world"
 >>> list(a)
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
>>> tuple(a)
('h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd')

Eine Verwendung von maphier wäre, wenn Sie mit einer Liste von Zeichenfolgen anstelle einer einzelnen Zeichenfolge beginnen - mapkönnen Sie alle einzeln auflisten:

>>> a = ["foo", "bar", "baz"]
>>> list(map(list, a))
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

Beachten Sie, dass map(list, a)dies in Python 2 äquivalent ist, aber in Python 3 benötigen Sie den listAufruf, wenn Sie etwas anderes tun möchten, als ihn in eine forSchleife einzuspeisen (oder eine Verarbeitungsfunktion wie sumdiese benötigt nur eine iterierbare und keine Sequenz). Beachten Sie aber auch noch einmal, dass ein Listenverständnis normalerweise bevorzugt wird:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]
lvc
quelle
map (fun x -> (x, x)) scheint nicht schwer zu verstehen ... (obwohl es unmöglich wäre, ein echtes kartesisches Produkt aus der Map herauszuholen, ist alles, was die Map produziert, immer eine Form einer Liste)
Kristopher Micinski
36

map Erstellt eine neue Liste, indem auf jedes Element der Quelle eine Funktion angewendet wird:

xs = [1, 2, 3]

# all of those are equivalent — the output is [2, 4, 6]
# 1. map
ys = map(lambda x: x * 2, xs)
# 2. list comprehension
ys = [x * 2 for x in xs]
# 3. explicit loop
ys = []
for x in xs:
    ys.append(x * 2)

n-ary mapentspricht dem gemeinsamen Zippen von Eingabeiterablen und dem anschließenden Anwenden der Transformationsfunktion auf jedes Element dieser gezippten Zwischenliste. Es ist kein kartesisches Produkt:

xs = [1, 2, 3]
ys = [2, 4, 6]

def f(x, y):
    return (x * 2, y // 2)

# output: [(2, 1), (4, 2), (6, 3)]
# 1. map
zs = map(f, xs, ys)
# 2. list comp
zs = [f(x, y) for x, y in zip(xs, ys)]
# 3. explicit loop
zs = []
for x, y in zip(xs, ys):
    zs.append(f(x, y))

Ich habe es ziphier verwendet, aber das mapVerhalten unterscheidet sich geringfügig, wenn iterables nicht dieselbe Größe haben. Wie in der Dokumentation angegeben, werden iterables erweitert None.

Cat Plus Plus
quelle
1
kompliziert, versuchen, diesen Beitrag zu verdauen
Web Master
1
@WebMaster Was ist daran kompliziert?
Jossie Calderon
Beste Antwort meiner Meinung nach. Die Verwendung des Lambda im Beispiel als Funktion macht dies sehr deutlich.
Sheldonzy
Leider sind all diese nicht gleichwertig - die Ausgabe dient [2,4,6]dem Listenverständnis und den expliziten Schleifen, aber die Karte gibt ein Kartenobjekt zurück - zum Beispiel bekomme ich folgendes: <map at 0x123a49978>Was ich dann in eine Liste zwingen muss.
Leerssej
20

Wenn Sie es ein wenig vereinfachen, können Sie sich vorstellen map(), so etwas zu tun:

def mymap(func, lst):
    result = []
    for e in lst:
        result.append(func(e))
    return result

Wie Sie sehen können, werden eine Funktion und eine Liste verwendet und eine neue Liste zurückgegeben, mit dem Ergebnis, dass die Funktion auf jedes der Elemente in der Eingabeliste angewendet wird. Ich sagte : „Vereinfachung ein wenig“ , denn in Wirklichkeit map()verarbeiten kann mehr als ein iterable:

Wenn zusätzliche iterierbare Argumente übergeben werden, muss die Funktion so viele Argumente annehmen und wird parallel auf die Elemente aller iterierbaren Argumente angewendet. Wenn eine Iterable kürzer als eine andere ist, wird angenommen, dass sie um Keine Elemente erweitert wird.

Für den zweiten Teil der Frage: Welche Rolle spielt dies bei der Herstellung eines kartesischen Produkts? Nun, map() könnte verwendet werden, um das kartesische Produkt einer Liste wie dieser zu erzeugen:

lst = [1, 2, 3, 4, 5]

from operator import add
reduce(add, map(lambda i: map(lambda j: (i, j), lst), lst))

... Aber um die Wahrheit zu sagen, ist die Verwendung product()eine viel einfachere und natürlichere Methode, um das Problem zu lösen:

from itertools import product
list(product(lst, lst))

In jedem Fall ist das Ergebnis das kartesische Produkt lstwie oben definiert:

[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
 (2, 1), (2, 2), (2, 3), (2, 4), (2, 5),
 (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5),
 (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]
Óscar López
quelle
17

Die map()Funktion dient dazu, auf jedes Element in einer iterierbaren Datenstruktur wie Listen, Generatoren, Zeichenfolgen und andere Elemente dieselbe Prozedur anzuwenden.

Schauen wir uns ein Beispiel an: map()Kann jedes Element in einer Liste durchlaufen und eine Funktion auf jedes Element anwenden, dann wird die neue Liste zurückgegeben (Sie erhalten sie zurück).

Stellen Sie sich vor, Sie haben eine Funktion, die eine Zahl nimmt, dieser Zahl 1 hinzufügt und sie zurückgibt:

def add_one(num):
  new_num = num + 1
  return new_num

Sie haben auch eine Liste von Nummern:

my_list = [1, 3, 6, 7, 8, 10]

Wenn Sie jede Zahl in der Liste erhöhen möchten, können Sie Folgendes tun:

>>> map(add_one, my_list)
[2, 4, 7, 8, 9, 11]

Hinweis: Benötigt mindestens map()zwei Argumente. Erstens ein Funktionsname und zweitens so etwas wie eine Liste.

Mal sehen, was andere coole Dinge map()können. map()Sie können mehrere Iterables (Listen, Zeichenfolgen usw.) verwenden und ein Element von jedem Iterable als Argument an eine Funktion übergeben.

Wir haben drei Listen:

list_one = [1, 2, 3, 4, 5]
list_two = [11, 12, 13, 14, 15]
list_three = [21, 22, 23, 24, 25]

map() Sie können eine neue Liste erstellen, in der Elemente an einem bestimmten Index hinzugefügt werden.

Denken Sie jetzt daran map(), braucht eine Funktion. Dieses Mal verwenden wir die eingebaute sum()Funktion. Laufen map()ergibt folgendes Ergebnis:

>>> map(sum, list_one, list_two, list_three)
[33, 36, 39, 42, 45]

ERINNERN SIE SICH:
In Python 2 map()wird gemäß der längsten Liste iteriert (die Elemente der Listen durchlaufen) und Nonean die Funktion für die kürzeren Listen übergeben, sodass Ihre Funktion diese suchen Noneund verarbeiten sollte, da sonst Fehler auftreten. In Python wird 3 beendet map(), nachdem die kürzeste Liste abgeschlossen wurde. Gibt in Python 3 auch map()einen Iterator zurück, keine Liste.

BlooB
quelle
8

Python3 - Karte (func, iterierbar)

Eine Sache, die nicht vollständig erwähnt wurde (obwohl @BlooB es irgendwie erwähnt hat), ist, dass map ein Kartenobjekt zurückgibt, KEINE Liste. Dies ist ein großer Unterschied in Bezug auf die Zeitleistung bei der Initialisierung und Iteration. Betrachten Sie diese beiden Tests.

import time
def test1(iterable):
    a = time.clock()
    map(str, iterable)
    a = time.clock() - a

    b = time.clock()
    [ str(x) for x in iterable ]
    b = time.clock() - b

    print(a,b)


def test2(iterable):
    a = time.clock()
    [ x for x in map(str, iterable)]
    a = time.clock() - a

    b = time.clock()
    [ str(x) for x in iterable ]
    b = time.clock() - b

    print(a,b)


test1(range(2000000))  # Prints ~1.7e-5s   ~8s
test2(range(2000000))  # Prints ~9s        ~8s

Wie Sie sehen, dauert die Initialisierung der Kartenfunktion fast gar nicht. Das Durchlaufen des Kartenobjekts dauert jedoch länger als das einfache Durchlaufen des iterierbaren Objekts. Dies bedeutet, dass die an map () übergebene Funktion nicht auf jedes Element angewendet wird, bis das Element in der Iteration erreicht ist. Wenn Sie eine Liste wünschen, verwenden Sie das Listenverständnis. Wenn Sie vorhaben, in einer for-Schleife zu durchlaufen und irgendwann abbrechen, verwenden Sie map.

Ranga
quelle