Hiểu chức năng bản đồ


311
map(function, iterable, ...)

Áp dụng chức năng cho mọi mục của iterable và trả về danh sách kết quả. Nếu các đối số lặp bổ sung được thông qua, hàm phải lấy nhiều đối số đó và được áp dụng cho các mục từ tất cả các lần lặp song song.

Nếu một lần lặp ngắn hơn lần lặp khác, nó được coi là được mở rộng với Không có mục nào.

Nếu chức năng là None, chức năng nhận dạng được giả định; nếu có nhiều đối số, map()trả về một danh sách bao gồm các bộ chứa các mục tương ứng từ tất cả các lần lặp (một loại hoạt động chuyển vị).

Các đối số lặp có thể là một chuỗi hoặc bất kỳ đối tượng lặp lại nào; kết quả luôn luôn là một danh sách.

Điều này đóng vai trò gì trong việc tạo ra một sản phẩm của Cartesian?

content = map(tuple, array)

Có ảnh hưởng gì đến việc đặt một tuple ở bất cứ đâu trong đó không? Tôi cũng nhận thấy rằng không có chức năng bản đồ, đầu ra là abcvà với nó, nó a, b, c.

Tôi muốn hiểu đầy đủ chức năng này. Các định nghĩa tham khảo cũng khó hiểu. Quá nhiều lông tơ ưa thích.


2
Những gì bạn thực sự muốn đạt được và tại sao cụ thể bạn muốn sử dụng map?
Kris Harper

3
@WebMaster có, mỗi câu đầu tiên trong tài liệu mà bạn đã dán - "Áp dụng chức năng cho mọi mục có thể lặp lại". Phần còn lại của đoạn nói về các trường hợp phức tạp hơn - như map(None, a, b, c)hóa ra để làm zip(a, b, c). Nhưng bạn rất hiếm khi thấy điều đó trong thực tế, chính xác bởi vì zipcuộc gọi là tương đương.
lvc

9
Tôi đang cố gắng học python và bất cứ khi nào tôi mở ra một định nghĩa trong python.org. Sau câu đầu tiên, tôi không hiểu gì cả. Ổn thỏa. cảm ơn bạn.
Web Master

2
tuplelà một hàm (tốt, nhiều sắc thái hơn thế, nhưng nó hoạt động giống như một hàm) có thể lặp lại và cung cấp cho bạn một tuple với các phần tử tương tự - vì vậy tuple([1, 2, 3])tương đương với (1, 2, 3). Đối với map(tuple, array), arraysẽ là một lần lặp của các lần lặp (nghĩ một danh sách các danh sách) và nó đưa bạn trở lại mỗi danh sách bên trong biến thành một tuple.
lvc

1
Nói chung, đó là câu đầu tiên của tài liệu về bất kỳ chức năng nào quan trọng nhất. Nếu bạn hiểu điều đó, bạn sẽ có được ý chính của nó. Phần còn lại của nó chỉ định hành vi rất chi tiết, và một số trong đó sẽ hơi mờ khi bắt đầu, và bạn có thể cần phải gặp một thành ngữ kỳ lạ dựa trên nó trước khi bạn thấy "oh, đó là điều đó có nghĩa là gì!". Nhưng một khi bạn có được khoảnh khắc bóng đèn đó cho một vài nội dung, bạn sẽ bắt đầu có thể hiểu các tài liệu dễ dàng hơn một chút.
lvc

Câu trả lời:


441

mapkhông đặc biệt là pythonic. Tôi sẽ khuyên bạn nên sử dụng danh sách hiểu thay thế:

map(f, iterable)

về cơ bản là tương đương với:

[f(x) for x in iterable]

maptự nó không thể làm một sản phẩm của Cartesian, vì độ dài của danh sách đầu ra luôn giống với danh sách đầu vào của nó. Bạn có thể làm một cách tầm thường một sản phẩm của Cartesian với sự hiểu biết về danh sách:

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

Cú pháp hơi khó hiểu - về cơ bản tương đương với:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))

36
Tôi thấy việc sử dụng mapít dài dòng hơn nhiều so với việc hiểu danh sách, ít nhất là đối với trường hợp bạn đang trình diễn.
marbel

1
Làm cách nào để sử dụng bản đồ cho các thuộc tính? Là gì map-equivalent của [v.__name__ for v in (object, str)]?
Một Sz

@ASz thế nào map(lambda v: v.__name__, list)?
Kilian

10
bản đồ nhanh hơn vì nó không gọi các chức năng dựa trên độ dài của các trình lặp .. các chức năng gọi có phí .. Xem 6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati

1
@anati tôi nghĩ mapđôi khi nhanh hơn comprehensions, đôi khi không, chính vì chức năng cuộc gọi trên không? Cụ thể, heuristic tôi học được là khi sử dụng mapđòi hỏi bạn phải giới thiệu một cuộc gọi chức năng bổ sung, hiểu nhanh hơn? Ví dụ, tôi đã được tin rằng map(lambda foo: foo.bar, my_list)chậm hơn foo.bar for foo in my_list, và thậm chí còn map(operator.add, my_list_of_pairs)chậm hơn x + y for x, y in my_list_of_pairs, chính xác là do cuộc gọi chức năng bổ sung.
mtraceur

86

maphoàn toàn không liên quan đến một sản phẩm của Cartesian, mặc dù tôi tưởng tượng ai đó thành thạo lập trình chức năng có thể đưa ra một số cách không thể hiểu để tạo ra một sản phẩm sử dụng map.

map trong Python 3 tương đương với điều này:

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

và sự khác biệt duy nhất trong Python 2 là nó sẽ xây dựng một danh sách đầy đủ các kết quả để trả về tất cả cùng một lúc thay vì yielding.

Mặc dù quy ước Python thường ưu tiên việc hiểu danh sách (hoặc biểu thức trình tạo) để đạt được kết quả tương tự như một lệnh gọi map, đặc biệt nếu bạn đang sử dụng biểu thức lambda làm đối số đầu tiên:

[func(i) for i in iterable]

Như một ví dụ về những gì bạn đã yêu cầu trong các nhận xét về câu hỏi - "biến một chuỗi thành một mảng", bằng 'mảng', bạn có thể muốn một tuple hoặc một danh sách (cả hai đều hoạt động giống như các mảng từ các ngôn ngữ khác) -

 >>> 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')

Việc sử dụng mapở đây sẽ là nếu bạn bắt đầu với một danh sách các chuỗi thay vì một chuỗi - mapcó thể liệt kê tất cả các chuỗi đó một cách riêng lẻ:

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

Lưu ý rằng map(list, a)tương đương với Python 2, nhưng trong Python 3, bạn cần listcuộc gọi nếu bạn muốn làm bất cứ điều gì khác ngoài việc đưa nó vào một forvòng lặp (hoặc một hàm xử lý như sumchỉ cần lặp lại chứ không phải chuỗi). Nhưng cũng lưu ý một lần nữa rằng việc hiểu danh sách thường được ưu tiên:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

map (fun x -> (x, x)) có vẻ không khó hiểu ... (mặc dù việc đưa một sản phẩm cartesian thực sự ra khỏi bản đồ là không thể, bất cứ thứ gì bản đồ tạo ra luôn là một dạng của danh sách)
Kristopher Micinski

36

map tạo một danh sách mới bằng cách áp dụng một hàm cho mọi phần tử của nguồn:

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 maptương đương với việc nén các lần lặp đầu vào với nhau và sau đó áp dụng hàm biến đổi trên mọi phần tử của danh sách nén trung gian đó. Đây không phải là sản phẩm của Cartesian:

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))

Tôi đã sử dụng zipở đây, nhưng maphành vi thực sự khác nhau một chút khi các lần lặp không có cùng kích thước - như đã lưu ý trong tài liệu của nó, nó mở rộng các lần lặp để chứa None.


1
phức tạp, cố gắng tiêu hóa bài đăng này
Web Master

1
@WebMaster Có gì phức tạp về nó?
Jossie Calderon

Câu trả lời tốt nhất theo ý kiến ​​của tôi. Sử dụng lambda trong ví dụ như một hàm làm cho nó rất rõ ràng.
sheldonzy

Thật không may, tất cả những thứ này không tương đương - đầu ra là [2,4,6]để hiểu danh sách và các vòng lặp rõ ràng, nhưng bản đồ trả về một đối tượng bản đồ - ví dụ tôi nhận được điều này: <map at 0x123a49978>Sau đó tôi phải ép buộc vào một danh sách.
leerssej

20

Đơn giản hóa một chút, bạn có thể tưởng tượng map()làm một cái gì đó như thế này:

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

Như bạn có thể thấy, nó nhận một hàm và một danh sách và trả về một danh sách mới với kết quả là áp dụng hàm cho từng phần tử trong danh sách đầu vào. Tôi đã nói "đơn giản hóa một chút" bởi vì trong thực tế map()có thể xử lý nhiều hơn một lần lặp:

Nếu các đối số lặp bổ sung được thông qua, hàm phải lấy nhiều đối số đó và được áp dụng cho các mục từ tất cả các lần lặp song song. Nếu một lần lặp ngắn hơn lần lặp khác, nó được coi là được mở rộng với Không có mục nào.

Đối với phần thứ hai trong câu hỏi: Vai trò này đóng vai trò gì trong việc tạo ra một sản phẩm của Cartesian? tốt, map() có thể được sử dụng để tạo ra sản phẩm cartesian của một danh sách như thế này:

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

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

... Nhưng nói thật, sử dụng product()là cách đơn giản và tự nhiên hơn nhiều để giải quyết vấn đề:

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

Dù bằng cách nào, kết quả là sản phẩm cartesian lstnhư được định nghĩa ở trên:

[(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)]

17

Các map()chức năng là có để áp dụng các thủ tục tương tự cho tất cả các mục trong một cấu trúc dữ liệu iterable, như danh sách, máy phát điện, dây, và các công cụ khác.

Hãy xem xét một ví dụ: map()có thể lặp lại mọi mục trong danh sách và áp dụng chức năng cho từng mục, hơn là nó sẽ trả về (trả lại cho bạn) danh sách mới.

Hãy tưởng tượng bạn có một hàm lấy một số, thêm 1 vào số đó và trả về nó:

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

Bạn cũng có một danh sách các số:

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

nếu bạn muốn tăng mọi số trong danh sách, bạn có thể làm như sau:

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

Lưu ý: Tối thiểu map()cần hai đối số. Đầu tiên một tên hàm và thứ hai giống như một danh sách.

Chúng ta hãy xem một số điều thú vị khác map()có thể làm. map()có thể lấy nhiều iterables (danh sách, chuỗi, v.v.) và truyền một phần tử từ mỗi iterable cho một hàm làm đối số.

Chúng tôi có ba danh sách:

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

map() có thể làm cho bạn một danh sách mới chứa thêm các yếu tố tại một chỉ mục cụ thể.

Bây giờ hãy nhớ map(), cần một chức năng. Lần này chúng ta sẽ sử dụng sum()hàm dựng sẵn . Chạy map()cho kết quả như sau:

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

HÃY NHỚ:
Trong Python 2 map(), sẽ lặp lại (đi qua các phần tử của danh sách) theo danh sách dài nhất và chuyển Noneđến hàm cho các danh sách ngắn hơn, vì vậy hàm của bạn sẽ tìm Nonevà xử lý chúng, nếu không bạn sẽ gặp lỗi. Trong Python 3 map()sẽ dừng lại sau khi kết thúc với danh sách ngắn nhất. Ngoài ra, trong Python 3, map()trả về một trình vòng lặp chứ không phải danh sách.


8

Python3 - bản đồ (func, lặp lại)

Một điều không được đề cập hoàn toàn (mặc dù @BlooB đã đề cập đến nó) là bản đồ trả về một đối tượng bản đồ KHÔNG phải là danh sách. Đây là một sự khác biệt lớn khi nói đến hiệu suất thời gian khi khởi tạo và lặp lại. Hãy xem xét hai bài kiểm tra này.

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

Như bạn có thể thấy việc khởi tạo chức năng bản đồ hầu như không mất thời gian. Tuy nhiên, việc lặp qua đối tượng bản đồ mất nhiều thời gian hơn chỉ đơn giản là lặp qua lần lặp. Điều này có nghĩa là hàm được truyền cho map () không được áp dụng cho mỗi phần tử cho đến khi phần tử được đạt tới trong lần lặp. Nếu bạn muốn một danh sách sử dụng hiểu danh sách. Nếu bạn có kế hoạch lặp lại trong một vòng lặp for và sẽ phá vỡ tại một số điểm, sau đó sử dụng bản đồ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.