25

我正在尝试map在 Python3 中使用。这是我正在使用的一些代码:

import csv

data = [
    [1],
    [2],
    [3]
]

with open("output.csv", "w") as f:
    writer = csv.writer(f)
    map(writer.writerow, data)

但是,由于map在 Python3 中返回一个迭代器,因此该代码在 Python3 中不起作用(但在 Python2 中可以正常工作,因为该版本map总是返回 a list

我目前的解决方案是list在迭代器上添加一个函数调用来强制评估。但这似乎很奇怪(我不在乎返回值,为什么要将迭代器转换为列表?)

有更好的解决方案吗?

4

6 回答 6

29

即使在 Python2.x 中,当您对返回值不感兴趣时​​使用map它的副作用(例如函数调用)也是不可取的。如果函数返回None,但重复了一百万次 - 你将构建一个一百万None的列表只是为了丢弃它。正确的方法是使用 for 循环并调用:

for row in data:
    writer.writerow(row)

或者在csv模块允许的情况下,使用:

writer.writerows(data)

如果出于某种原因您真的非常想使用map,那么您可以使用consumeitertools 中的配方并生成一个零长度的双端队列,例如:

from collections import deque
deque(map(writer.writerow, data), maxlen=0)
于 2013-08-25T20:44:49.863 回答
6

您可以设置一个零长度的双端队列来执行此操作:

with open("output.csv", "w") as f:
    writer = csv.writer(f)
    collections.deque(map(writer.writerow, data),0)

这与itertools.consume(iterator, None)配方的工作方式相同。它在功能上将耗尽迭代器而不构建列表。

您也可以只使用.itertools

但是循环对我来说更具可读性和 Pythonic,但是 YMMV。

于 2013-08-25T20:55:09.297 回答
3

如果您不关心返回值,那么map这不是工作的最佳工具。一个简单的for会更好:

for d in data:
    writer.writerow(d)

这在 Python 2.x 和 3.x 中可以正常工作。请注意,map当您想创建一个新列表时,这很有用,如果您只是为了效果而遍历一个可迭代对象,则使用for.

于 2013-08-25T20:44:26.987 回答
2
list(map(lambda x: do(x),y))

将触发评估并保持良好、可读的语义,从而提高人类运行时的效率,超越“for-loop(这是一个映射本身)加上新的段落范围转换”语义。¯\ (ツ)

请注意,在初稿中没有理由不将其称为语义糖(事实上,for 循环通常更容易,因为它们更加模块化:在第一次尝试解决问题时,您可能不知道代码需要做什么),但是,当您对处于工作状态的代码进行生产化或逆向工程时,提高语义效率(或者甚至只是用相当好的代码重写)是成功的重要因素。

无论如何,如果要刷新堆栈,请通过类型转换map触发它。list


所以:

import csv

data = [
    [1],
    [2],
    [3]
]

with open("output.csv", "w") as f:
    writer = csv.writer(f)
    list(map(writer.writerow, data))
于 2020-09-02T15:51:21.150 回答
1

您还可以按照官方常见问题解答中的建议使用列表推导:

with open("output.csv", "w") as f:
    writer = csv.writer(f)
    [writer.writerow(elem) for elem in data]

即使您没有将新创建的列表分配给任何变量,列表理解也会强制评估每个元素。

但是请注意,该列表仍可能在幕后创建,从而造成潜在的性能缺陷,因此虽然相对简洁,但如果输入序列可能会变得很长,则不应使用它。

于 2019-03-13T12:42:19.753 回答
0

我会使用这样的函数从可迭代对象中提取数据:

def rake(what, where=None):
    for i in what: 
        if where: where.append(i)

rake(map(writer.writerow, data))

如果您事先知道您永远不会收集映射函数的输出,那么您可以将其简化为:

for i in what: pass

但是这两种方法都不会保留多余的数据,除非你提供一个列表来放入它。而且这种方法应该同样适用于 map、filter、reduce、generators、range 以及任何你可以传递给 rake 函数的东西迭代。

于 2018-10-04T05:35:30.997 回答