我正在尝试用Python编写Haskel函数’splitEvery’。这是它的定义:
splitEvery :: Int -> [e] -> [[e]] @'splitEvery' n@ splits a list into length-n pieces. The last piece will be shorter if @n@ does not evenly divide the length of the list.
这个的基本版本工作正常,但是我想要一个可以与生成器表达式,列表和迭代器一起使用的版本。 并且 ,如果有一个生成器作为输入,则应该返回一个生成器作为输出!
# should not enter infinite loop with generators or lists splitEvery(itertools.count(), 10) splitEvery(range(1000), 10) # last piece must be shorter if n does not evenly divide assert splitEvery(5, range(9)) == [[0, 1, 2, 3, 4], [5, 6, 7, 8]] # should give same correct results with generators tmp = itertools.islice(itertools.count(), 10) assert list(splitEvery(5, tmp)) == [[0, 1, 2, 3, 4], [5, 6, 7, 8]]
这是我当前拥有的代码,但不适用于简单的列表。
def splitEvery_1(n, iterable): res = list(itertools.islice(iterable, n)) while len(res) != 0: yield res res = list(itertools.islice(iterable, n))
此代码不适用于生成器表达式(感谢软糖修复该表达式):
def splitEvery_2(n, iterable): return [iterable[i:i+n] for i in range(0, len(iterable), n)]
必须有一个简单的代码来进行拆分。我知道我可以具有不同的功能,但看起来应该是一件容易的事。我可能陷入了一个不重要的问题,但这确实困扰了我。
它类似于http://docs.python.org/library/itertools.html#itertools.groupby中的分组器,但我不希望它填充额外的值。
def grouper(n, iterable, fillvalue=None): "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" args = [iter(iterable)] * n return izip_longest(fillvalue=fillvalue, *args)
它确实提到了截断最后一个值的方法。这也不是我想要的。
保证了可迭代对象的从左到右的评估顺序。这使得使用izip(* [iter(s)] * n)将数据系列聚类为n个长度的组成为可能。
list(izip(*[iter(range(9))]*5)) == [[0, 1, 2, 3, 4]] # should be [[0, 1, 2, 3, 4], [5, 6, 7, 8]]
from itertools import islice def split_every(n, iterable): i = iter(iterable) piece = list(islice(i, n)) while piece: yield piece piece = list(islice(i, n))
一些测试:
>>> list(split_every(5, range(9))) [[0, 1, 2, 3, 4], [5, 6, 7, 8]] >>> list(split_every(3, (x**2 for x in range(20)))) [[0, 1, 4], [9, 16, 25], [36, 49, 64], [81, 100, 121], [144, 169, 196], [225, 256, 289], [324, 361]] >>> [''.join(s) for s in split_every(6, 'Hello world')] ['Hello ', 'world'] >>> list(split_every(100, [])) []