理解映射函数

Python 2文档说:

内置函数:map(function, iterable, ...)

将函数应用于iterable的每个项,并返回一个列表 结果。如果传递了额外的可迭代参数,则function必须 取这么多参数,应用于所有项

如果一个可迭代对象比另一个可迭代对象短,则认为它是可扩展的

如果function为None,则假设是恒等函数;如果有 如果有多个参数,map()将返回一个由元组组成的列表 包含来自所有可迭代对象的对应项(一种 转置操作)。< / p > 可迭代实参可以是一个序列或任何可迭代对象;的 结果总是一个列表

它在笛卡尔积中起什么作用呢?

content = map(tuple, array)

把一个元组放在那里有什么影响?我还注意到,如果没有map函数,输出是abc,而有了它,输出是a, b, c

我想完全理解这个函数。参考定义也很难理解。太多花哨的绒毛。

507922 次浏览

map根本与笛卡尔积无关,尽管我认为精通函数式编程的人可能会想出一些难以理解的方法来使用map生成一个。

map在python3中等价于:

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

Python 2中唯一的区别是,它将构建一个完整的结果列表来一次性返回,而不是yielding。

尽管Python惯例通常倾向于使用列表推导式(或生成器表达式)来实现与调用map相同的结果,特别是当你使用lambda表达式作为第一个参数时:

[func(i) for i in iterable]

作为你在问题评论中要求的一个例子-“将字符串转换为数组”,通过“数组”,你可能想要一个元组或一个列表(它们的行为有点像其他语言中的数组)-

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

这里使用map的情况是,如果你从一个字符串的列表开始,而不是一个字符串——map可以单独列出所有字符串:

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

注意,map(list, a)在Python 2中是等效的,但在Python 3中,如果你想做任何事情,而不是将其送入for循环(或像sum这样只需要可迭代对象而不需要序列的处理函数),则需要list调用。但也要再次注意,通常首选列表推导式:

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

map通过对源的每个元素应用函数来创建一个新列表:

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 map等价于将输入可迭代对象压缩在一起,然后对中间压缩列表的每个元素应用转换函数。它是笛卡尔积:

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

我在这里使用了zip,但是当可迭代对象的大小不同时,map的行为实际上略有不同——正如它的文档中所指出的,它扩展了可迭代对象以包含None

map不是特别python化的。我建议使用列表推导式:

map(f, iterable)

基本上相当于:

[f(x) for x in iterable]

map本身不能做笛卡尔积,因为它的输出列表的长度总是与它的输入列表相同。你可以简单地用一个列表推导做一个笛卡尔积:

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

语法有点混乱——基本上相当于:

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

简化一点,你可以想象map()做这样的事情:

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

如您所见,它接受一个函数和一个列表,并返回一个新列表,其中包含将该函数应用于输入列表中的每个元素的结果。我说“简化一点”是因为在现实中map()可以处理不止一个可迭代对象:

如果传递了额外的可迭代参数,则function必须接受相同数量的参数,并并行应用于所有可迭代对象中的项。如果一个可迭代对象比另一个短,则假定它扩展为None项。

问题的第二部分,这个在笛卡尔积中扮演什么角色?嗯,map() 可以可用于生成如下列表的笛卡尔积:

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


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

... 但说实话,使用product()是一种更简单和自然的解决问题的方法:

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

无论哪种方式,结果都是上面定义的lst的笛卡尔积:

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

map()函数用于对可迭代数据结构中的每个项应用相同的过程,如列表、生成器、字符串和其他东西。

让我们看一个例子: map()可以遍历列表中的每一项,并对每一项应用函数,然后它将返回(返回)新列表

假设你有一个函数,它接受一个数字,将这个数字加1并返回它:

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

你还有一个数字列表:

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

如果您想增加列表中的每个数字,您可以执行以下操作:

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

注意:至少map()需要两个参数。首先是函数名,其次是类似于列表的东西。

让我们看看map()可以做的其他一些很酷的事情。 map()可以接受多个可迭代对象(列表、字符串等),并将每个可迭代对象中的一个元素作为参数传递给函数

我们有三个列表:

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

map()可以创建一个新列表,其中包含特定下标处添加的元素。

现在记住map()需要一个函数。这次我们将使用内置的sum()函数。运行map()会得到以下结果:

>>> map(sum, list_one, list_two, list_three)
[33, 36, 39, 42, 45]
< p > 记住: < br > 在Python 2 map()中,将根据最长的列表进行迭代(遍历列表中的元素),并将None传递给较短列表的函数,因此您的函数应该查找None并处理它们,否则将得到错误。在Python 3中,map()将在完成最短列表后停止。此外,在Python 3中,map()返回一个迭代器,而不是一个列表

Python3 - map(func, iterable)

有一件事没有完全提到(尽管@BlooB提到了),map返回一个map对象一个列表。当涉及到初始化和迭代的时间性能时,这是一个很大的区别。考虑这两个测试。

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

如您所见,初始化map函数几乎不需要花费任何时间。然而,遍历map对象要比遍历iterable花费更长的时间。这意味着传递给map()的函数在迭代中到达元素之前不会应用到每个元素。如果你想要一个列表,使用列表理解。如果您计划在for循环中遍历,并且将在某个点中断,那么请使用map。