获取map()以在Python 3.x中返回列表


523

我正在尝试将列表映射为十六进制,然后在其他地方使用该列表。在python 2.6中,这很简单:

答: Python 2.6:

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

但是,在Python 3.1中,以上代码返回一个map对象。

B: Python 3.1:

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

如何在Python 3.x上检索映射列表(如上面的A所示)?

另外,还有更好的方法吗?我的初始列表对象大约有45个项目,并且id喜欢将它们转换为十六进制。


2
使用列表推导更具Python map()几乎是从语言删除,因为没有任何理由使用它在列表中理解或for循环。
鲍里斯(Boris)

Answers:


771

做这个:

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

在Python 3+中,许多迭代可迭代对象的进程本身都会返回迭代器。在大多数情况下,这最终会节省内存,并且应该使处理速度更快。

如果您要做的只是最终遍历此列表,则无需将其转换为列表,因为您仍然可以map像这样遍历该对象:

# Prints "ABCD"
for ch in map(chr,[65,66,67,68]):
    print(ch)

15
当然,您也可以对此进行迭代:([65,66,67,68]中x的chr(x))。它甚至不需要地图。
hughdbrown

2
@hughdbrown map在复杂函数,大型数据集或流上进行迭代时,使用3.1的参数将是惰性计算。
安德鲁·基顿

18
@Andrew实际上Hugh正在使用生成器理解,它会做同样的事情。请注意括号而不是方括号。
三联画

5
当值已知为ASCII / latin-1时,备用解决方案(对于大型输入也更快)将在C层进行批量转换:bytes(sequence_of_ints_in_range_0_to_256).decode('latin-1')str避免了对每个元素的Python函数调用,而支持C的批量转换,从而加快了转换速度所有元素仅使用C级函数调用。list如果确实需要list单个字符,则可以将以上内容包装起来,但是由于str已经是其自身字符的可迭代项,因此这样做的唯一原因是需要可变性。
ShadowRanger

1
list(map(str,[1,2,3]))在CentOS 7上给出Python 3.4.3的“参数错误”。
Andor

108

Python 3.5的新功能:

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

多亏了其他拆包概述

更新

一直在寻找更短的途径,我发现这也行得通:

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

开箱也适用于元组。注意最后的逗号。这使其成为1个元素的元组。也就是说,它相当于(*map(chr, [66, 53, 0, 94]),)

它比带有方括号的版本短一个字符,但我认为最好写,因为您从星号-扩展语法开始,所以我觉得它比较软。:)


11
@Quelklef list()看起来不那么整洁
Arijoon

5
@Quelklef:另外,由于不需要查找list构造函数和调用通用函数调用机制,因此解压缩方法的速度非常快。对于长时间的输入,这无关紧要;一小段时间,它可以带来很大的不同。使用上面的代码作为输入,tuple这样就不会重复重构它,微ipython基准测试表明list()包装方法比拆包要花费大约20%的时间。提醒您,绝对的,我们说的是150 ns,这是微不足道的,但是您明白了。
ShadowRanger

旧的map怎么了?lmap如果新的默认值是返回迭代器,也许使用新名称(?)?
乔治

1
*map()在上给出语法错误Python 3.6can't use starred expression here。您需要将其放在以下位置list[ *map() ]
ALH

4
@ALH您在命令末尾错过了逗号。容易犯的错误!
LondonRob

103

您为什么不这样做:

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

这称为列表理解。您可以在Google上找到很多信息,但是这里是list comprehensions上的Python(2.6)文档的链接。不过,您可能对Python 3文档更感兴趣。


4
嗯 也许需要在列表理解,生成器,map(),zip()以及python中的许多其他快速迭代优势方面进行一般性发布。
hughdbrown

46
我猜是因为它比较冗长,您必须编写一个额外的变量(两次)...如果操作更复杂并且最终编写了lambda,或者还需要删除一些元素,那么我认为理解肯定会更好比map + filter更好,但是如果您已经具有要应用的功能,则map更为简洁。
fortran

1
+1:更易于阅读,并允许您使用具有许多参数的功能
Le Droid

7
map(chr, [66,53,0,94])肯定比[chr(x) for x in [66,53,0,94]]
乔治

比其他答案更快的方式
Evhz

25

返回列表的地图功能具有保存键入的优点,尤其是在交互式会话期间。您可以定义返回列表的lmap函数(类似于python2的函数imap):

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

然后打电话 lmap而不是即可map完成工作:比 lmap(str, x)短5个字符(在这种情况下为30%),list(map(str, x))并且肯定比短[str(v) for v in x]。您也可以创建类似的功能filter

对原始问题有一条评论:

我建议重命名为Geting map()以返回Python 3. *中的列表,因为它适用于所有Python3版本。有没有办法做到这一点?– meawoppl 1月24日17:58

有可能做到这一点,但它是一个非常糟糕的主意。只是为了好玩,您可以(但不应)执行以下操作:

__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

4

我的旧注释转换为更好的可见性:为了更好地“更好地做到这一点” map,如果您的输入已知为ASCII序数,则通常可以更快地转换为bytesla bytes(list_of_ordinals).decode('ascii')。这样就可以得到一个str值,但是如果您需要a list来实现可变性或类似功能,则可以将其转换(并且转换速度仍然更快)。例如,在微ipython基准中转换45个输入:

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

如果您将其保留为str,则最快的map解决方案会花费大约20%的时间;即使转换回列表,它仍然不到最快map解决方案的40%。批量转换通过bytesbytes.decode然后批量转换回以list节省大量工作,但是如上所述,仅当您所有的输入都是ASCII序号(或每个字符特定于区域设置编码的字节中的序号latin-1)时,该方法才有效。


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

map(func,* iterables)->地图对象创建一个迭代器,该迭代器使用每个可迭代对象的参数来计算函数。当最短的迭代次数用尽时停止。

“进行迭代”

表示它将返回迭代器。

“使用每个可迭代对象的参数来计算函数”

意味着迭代器的next()函数将为每个可迭代对象取一个值,并将每个值传递给该函数的一个位置参数。

因此,您可以从map()函数中获得一个迭代器,然后jsut将其传递给内置函数list()或使用列表推导。


2

除了上述答案外Python 3,我们还可以简单地listmapas中创建结果值a

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

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

我们可以通过另一个例子来概括我被打动的情况,对地图的操作也可以像regex问题中一样的方式处理,我们可以编写函数以获取list要映射的项目并同时获取结果集。例如

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]

@miradulo我应该在Python 2中返回一个列表,但是在Python 3中,只返回类型,而我只是尝试给出相同的格式。如果您认为它没有必要,也许像我这样的人会发现它有用,这就是为什么我添加了它。
Harry_pb

2
如果已经有了列表理解,列表函数和拆包答案,则显式的for循环不会增加太多恕我直言。
miradulo

1

您可以尝试通过仅迭代对象中的每个项目并将其存储在另一个变量中来从地图对象获取列表。

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

0

使用python中的列表理解和基本的地图函数实用程序,还可以做到这一点:

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


chi列表将包含给定元素的ASIC值。
darshan ks
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.