了解地图功能


311
map(function, iterable, ...)

将函数应用于每个iterable项目,并返回结果列表。如果传递了其他可迭代参数,则函数必须采用那么多参数,并且并行地将其应用于所有可迭代对象的项。

如果一个可迭代项短于另一个可迭代项,则假定它扩展为None。

如果function是None,则假定身份函数;如果有多个参数,则map()返回一个由元组组成的列表,其中包含所有可迭代对象中的对应项(一种转置操作)。

可迭代参数可以是序列或任何可迭代对象。结果总是一个列表。

这在制作笛卡尔积时起什么作用?

content = map(tuple, array)

将元组放在任何地方会有什么作用?我也注意到,如果没有地图功能的输出abc,并与它,它的a, b, c

我想完全了解此功能。参考定义也很难理解。花哨的绒毛太多。


2
您实际上想要实现什么?为什么要具体使用map
克里斯·哈珀

3
@WebMaster是的,根据您粘贴的文档中的第一句话-“将函数应用于可迭代的每个项目”。本段的其余部分是关于更复杂的案例的,map(None, a, b, c)事实证明确实如此zip(a, b, c)。但是实际上,您很少会看到这种情况,因为zip调用是等效的。
lvc 2012年

9
我正在努力学习python,并且每当在python.org中打开一个定义时。第一句话之后,我什么都不懂。好的。谢谢。
Web Master

2
tuple是一个函数(需要一个可迭代的函数,并且为您提供具有相同元素的元组),因此tuple([1, 2, 3])等效于(1, 2, 3)。对于map(tuple, array)array将是一个可迭代的可迭代对象(请考虑一个列表列表),它使您可以将每个内部列表转换成一个元组。
lvc 2012年

1
通常,最重要的是所有功能文档的第一句话。如果您了解这一点,便可以理解。它的其余部分规定了非常详细的行为,以及一些这是一个有点不透明,开始时,你可能需要遇到基于它之前,你看到一个奇怪的成语“哦,是什么意思!”。但是一旦掌握了一些内置功能,您就应该能够更轻松地理解文档了。
lvc 2012年

Answers:


441

map不是特别的pythonic。我建议改用列表推导:

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

36
我发现使用map的冗长程度比列表理解要少得多,至少对于您所演示的情况而言。
marbel

1
如何将地图用于属性?的map-equivalent是[v.__name__ for v in (object, str)]什么?
Sz

@ASz怎么样map(lambda v: v.__name__, list)
基利安

10
map更快,因为它不会根据迭代器的长度来调用函数。.调用函数会产生开销..观看6:00 youtube.com/watch?v=SiXyyOA6RZg&t=813s
anati

1
@anati我还以为map有时快于内涵,有时没有,正是因为函数调用的开销?特别是,我学到的启发式方法是,当使用时map需要引入额外的函数调用时,理解会更快吗?例如,正是由于额外的函数调用,我才被认为map(lambda foo: foo.bar, my_list)比慢foo.bar for foo in my_list,甚至map(operator.add, my_list_of_pairs)比慢x + y for x, y in my_list_of_pairs
mtraceur

86

map尽管我想象一个精通函数式编程的人可能会提出一些无法理解的使用生成方法的方法,但它与笛卡尔积完全无关map

map Python 3中的等效于此:

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中,list如果您想要执行其他操作而不是将其馈入for循环(或诸如sum仅需要可迭代的处理函数,而无需序列)的处理函数,则需要调用。但也请注意,通常首选列表理解:

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

map(fun x->(x,x))似乎很难理解...(尽管不可能从地图中获得真正的笛卡尔积,但是地图产生的任何东西总是某种形式的列表)
Kristopher Micinski

36

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当可迭代项的大小不同时,行为实际上稍有不同–如其文档中所述,它将可迭代项扩展为contains None


1
复杂,试图消化该帖子
Web Master

1
@WebMaster它有什么复杂之处?
Jossie Calderon

我认为最好的答案。在示例中将lambda用作函数可以很清楚地看出。
sheldonzy

不幸的是,所有这些都不相同-输出是[2,4,6]用于列表理解和显式循环的,但是地图返回了地图对象-例如,我得到了这一点:<map at 0x123a49978>然后必须将其强制转换为列表。
leerssej

20

简化一下,您可以想象map()这样做:

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

如您所见,它接受一个函数和一个列表,并返回一个新列表,并将该函数应用于输入列表中的每个元素。我说“简化一点”是因为实际上map()可以处理多个迭代:

如果传递了其他可迭代参数,则函数必须采用那么多参数,并且并行地将其应用于所有可迭代对象的项。如果一个可迭代项短于另一个可迭代项,则假定它扩展为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)]

17

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]

记住:
在Python 2中map(),将根据最长的列表进行迭代(遍历列表中的元素),并传递None给较短列表的函数,因此您的函数应查找None并处理它们,否则会出错。在Python 3中map(),使用最短列表结束后将停止。同样,在Python 3中,map()返回迭代器,而不是列表。


8

Python3-映射(函数,可迭代)

没有完全提及的一件事(尽管@BlooB kinda提到了)是地图返回地图对象而不是列表。在初始化和迭代的时间性能方面,这是一个很大的差异。考虑这两个测试。

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对象进行迭代比仅简单地迭代可迭代对象要花费更长的时间。这意味着传递给map()的函数不会应用到每个元素,直到在迭代中到达该元素为止。如果要使用列表,请使用列表理解。如果您打算在for循环中进行迭代并且会在某个时候中断,请使用map。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.