遍历列表切片
我想要一个算法,可以对列表的切片进行遍历。切片的大小是在函数外部设置的,可能会有所不同。
我脑海中的想法是这样的:
for list_of_x_items in fatherList:
foo(list_of_x_items)
有没有办法正确地定义 list_of_x_items
,或者用其他方式在 Python 2.5 中实现这个功能呢?
编辑1:澄清 “分区”和“滑动窗口”这两个词听起来都适合我的任务,但我并不是专家。所以我会更深入地解释一下问题,并补充到问题中:
fatherList 是一个多层的 numpy.array,我是从一个文件中获取的。这个函数需要找到一系列的平均值(用户提供系列的长度)。我使用 mean()
函数来计算平均值。现在为了扩展问题:
编辑2:你提供的函数怎么修改,才能存储额外的项,并在下一个 fatherList 输入到函数时使用它们呢?
举个例子,如果列表的长度是 10,而每个块的大小是 3,那么列表的第 10 个成员会被存储,并在下一个列表的开头添加上。
相关链接:
10 个回答
如果你想要处理任何可以遍历的东西,可以使用这些函数:
from itertools import chain, islice
def ichunked(seq, chunksize):
"""Yields items from an iterator in iterable chunks."""
it = iter(seq)
while True:
yield chain([it.next()], islice(it, chunksize-1))
def chunked(seq, chunksize):
"""Yields items from an iterator in list chunks."""
for chunk in ichunked(seq, chunksize):
yield list(chunk)
如果你想把一个列表分成几块,可以用这个小技巧:
list_of_slices = zip(*(iter(the_list),) * slice_size)
举个例子:
>>> zip(*(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]
如果列表里的项目数量不能被切片大小整除,而你想用 None 来填充列表,可以这样做:
>>> map(None, *(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]
这其实是个小窍门。
好吧,我来解释一下这个技巧是怎么工作的。虽然有点复杂,但我会尽量讲清楚。
首先,先了解一些背景知识:
在 Python 中,你可以用一个数字来乘以一个列表,像这样:
[1, 2, 3] * 3 -> [1, 2, 3, 1, 2, 3, 1, 2, 3]
([1, 2, 3],) * 3 -> ([1, 2, 3], [1, 2, 3], [1, 2, 3])
还有一个 迭代器 对象只能被消费一次,像这样:
>>> l=iter([1, 2, 3])
>>> l.next()
1
>>> l.next()
2
>>> l.next()
3
zip 函数会返回一个元组的列表,其中第 i 个元组包含每个参数序列或可迭代对象的第 i 个元素。例如:
zip([1, 2, 3], [20, 30, 40]) -> [(1, 20), (2, 30), (3, 40)]
zip(*[(1, 20), (2, 30), (3, 40)]) -> [[1, 2, 3], [20, 30, 40]]
在 zip 前面的 * 是用来解包参数的。你可以在 这里 找到更多细节。
所以
zip(*[(1, 20), (2, 30), (3, 40)])
实际上等同于
zip((1, 20), (2, 30), (3, 40))
但可以处理可变数量的参数。
现在回到这个小技巧:
list_of_slices = zip(*(iter(the_list),) * slice_size)
iter(the_list)
-> 把列表转换成一个迭代器。
(iter(the_list),) * N
-> 这会生成 N 个对 the_list 迭代器的引用。
zip(*(iter(the_list),) * N)
-> 这会把这些迭代器的列表传给 zip。然后 zip 会把它们分组为 N 大小的元组。但因为这 N 个项目实际上都是对同一个迭代器 iter(the_list)
的引用,所以结果会是对原始迭代器的 next()
的重复调用。
希望这样解释清楚了。我建议你使用更容易理解的解决方案。我之所以提到这个技巧,是因为我觉得它很有意思。
对问题最后部分的回答:
问题更新:如何修改你提供的函数,以便存储额外的项目,并在下一个父列表传入函数时使用它们?
如果你需要保存状态,可以用一个对象来实现。
class Chunker(object):
"""Split `iterable` on evenly sized chunks.
Leftovers are remembered and yielded at the next call.
"""
def __init__(self, chunksize):
assert chunksize > 0
self.chunksize = chunksize
self.chunk = []
def __call__(self, iterable):
"""Yield items from `iterable` `self.chunksize` at the time."""
assert len(self.chunk) < self.chunksize
for item in iterable:
self.chunk.append(item)
if len(self.chunk) == self.chunksize:
# yield collected full chunk
yield self.chunk
self.chunk = []
例子:
chunker = Chunker(3)
for s in "abcd", "efgh":
for chunk in chunker(s):
print ''.join(chunk)
if chunker.chunk: # is there anything left?
print ''.join(chunker.chunk)
输出:
abc
def
gh