可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
list.extend and list comprehension
6 answers
I'm not experienced in Python, and I often write code that (simplified) looks like this:
accumulationList = []
for x in originalList:
y = doSomething(x)
accumulationList.append(y)
return accumulationList
Then after my test passes, I refactor to
return [doSomething(x) for x in originalList]
But suppose it turns out a little different, and my loop looks like this:
accumulationList = []
for x in originalList:
y = doSomething(x)
accumulationList.extend(y)
return accumulationList
where the doSomething
list returns a list. What is the most Pythonic way to accomplish this? Obviously, the previous list comprehension would give a list of lists.
回答1:
Much simpler and cleaner with list comprehension:
[y for x in originalList for y in doSomething(x)]
回答2:
Do you mean something like this?
accumulationList = []
for x in originalList:
accumulationList.extend(doSomething(x))
return accumulationList
or shorter code (but not optimal):
return sum((doSomething(x) for x in originalList), [])
or the same:
return sum(map(doSomething, originalList), [])
Thanks to @eyquem for the hint (if using Python 2.x):
import itertools as it
return sum(it.imap(doSomething, originalList), [])
回答3:
Python's in-place add operator (+=
, available as iadd
in operator
module) is equivalent of .extend
for list. Pair it with reduce
to get what you want.
import operator
reduce(operator.iadd, (doSomething(x) for x in originalList)
, accumulation_list)
回答4:
I think the answers involving add or iadd run in quadratic time, which probably isn't good. I'd try:
from itertools import chain
accumulation_list = list(chain.from_iterable(doSomething(x) for x in originalList))
回答5:
I don't think there is special syntax for this case. But you could make the for loop shorter:
accumulationList += doSomething(x)
If you insist, you could use functional programming to flatten the list:
result = reduce(lambda a,b: a+b, [[i,i*2] for i in range(3)])
But I wouldn't call this pythonic, I think it's harder to read than a for loop.
回答6:
Functionally, you can use itertools.chain
with map
. For an input list L
:
res = list(chain.from_iterable(map(doSomething, L)))
If you need an iterator, simply remove the list
call. Here's a demo:
def doSomething(value):
return [value * i for i in range(1, 4)]
def original(originalList):
accumulationList = []
for x in originalList:
y = doSomething(x)
accumulationList.extend(y)
return accumulationList
def new(L):
return list(chain.from_iterable(map(doSomething, L)))
x = [1, 2, 3]
assert original(x) == new(x)
print(new(x))
[1, 2, 3, 2, 4, 6, 3, 6, 9]