当前位置:  开发笔记 > 编程语言 > 正文

在块中迭代列表的最"pythonic"方法是什么?

如何解决《在块中迭代列表的最"pythonic"方法是什么?》经验,为你挑选了10个好方法。

我有一个Python脚本,它将整数列表作为输入,我需要一次使用四个整数.不幸的是,我无法控制输入,或者我将它作为四元素元组列表传入.目前,我正在以这种方式迭代它:

for i in xrange(0, len(ints), 4):
    # dummy op for example code
    foo += ints[i] * ints[i + 1] + ints[i + 2] * ints[i + 3]

它看起来很像"C-think",这让我怀疑有更多的pythonic方式来处理这种情况.迭代后会丢弃该列表,因此无需保留.也许这样的事情会更好吗?

while ints:
    foo += ints[0] * ints[1] + ints[2] * ints[3]
    ints[0:4] = []

但是,仍然没有"感觉"正确.: - /

相关问题:如何在Python中将列表拆分为大小均匀的块?



1> nosklo..:
def chunker(seq, size):
    return (seq[pos:pos + size] for pos in range(0, len(seq), size))
# (in python 2 use xrange() instead of range() to avoid allocating a list)

简单.简单.快速.适用于任何序列:

text = "I am a very, very helpful text"

for group in chunker(text, 7):
   print repr(group),
# 'I am a ' 'very, v' 'ery hel' 'pful te' 'xt'

print '|'.join(chunker(text, 10))
# I am a ver|y, very he|lpful text

animals = ['cat', 'dog', 'rabbit', 'duck', 'bird', 'cow', 'gnu', 'fish']

for group in chunker(animals, 3):
    print group
# ['cat', 'dog', 'rabbit']
# ['duck', 'bird', 'cow']
# ['gnu', 'fish']


@Carlos Crasborn的版本适用于任何可迭代的(不仅仅是上面代码的序列); 它简洁,可能同样快速甚至更快.虽然对于不熟悉`itertools`模块的人来说可能有点模糊(不清楚).
使用3.x我只需要用`range`替换`xrange`.请参阅:http://stackoverflow.com/a/15014576/671013
你可以直接编写一个生成器,使用`yield`:`for for xrange(0,len(seq),size):yield seq [pos:pos + size],而不是写一个函数构建然后返回一个生成器. `.我不确定在内部是否会在任何相关方面对其进行任何不同的处理,但它可能甚至更清晰一些.
注意`chunker`返回一个`generator`.将return替换为:`return [...]`以获取列表.
请注意,这仅适用于支持通过索引访问项目的序列,并且不适用于通用迭代器,因为它们可能不支持`__getitem__`方法.

2> Craz..:

从Python的itertools文档的recipes部分修改:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

示例
在伪代码中保持示例简洁.

grouper('ABCDEFG', 3, 'x') --> 'ABC' 'DEF' 'Gxx'

注意: izip_longest Python 2.6的新功能.在Python 3中使用zip_longest.


终于有机会在python会话中玩这个.对于那些和我一样困惑的人来说,这会多次向izip_longest提供相同的迭代器,导致它消耗相同序列的连续值,而不是单独序列中的条带值.我喜欢它!
在一些地方,评论者说"当我最终弄清楚它是如何工作的......"也许需要一些解释.特别是迭代器方面的列表.
我怀疑这个256k大小块的石斑鱼配方的性能会非常差,因为`izip_longest`将被输入256k参数.
过滤掉fillvalue的最佳方法是什么?(对于石斑鱼中的项目,可以使用项目中的项目,如果项目不是fillvalue)(可迭代))?
有没有办法使用“ None”填充最后一块呢?
我不确定这是否是最pythonic的答案,但它可能是`[LIST]*n`结构的最佳用法.
这有效,但似乎依赖于解释器实现.itertools.izip_longest规范是否实际上保证了迭代器的条带化访问顺序(例如,使用3个迭代器A,B和C,访问顺序将是A,B,C,A,B,C,A,Fill,C而不是A,A,B,B,C,C,A,Fill,C或A,B,C,C,B,A,A,Fill,C?我可以看到后面的顺序对缓存很有用线性能优化.如果不保证单条带访问顺序,这不是一个理论上安全的解决方案(虽然实际上说,大多数实现将单步迭代器).
@DavidB.:配方作为官方文档中的示例代码.除非它是一个bug; 这种行为是有保障的

3> S.Lott..:

我是粉丝

chunk_size= 4
for i in range(0, len(ints), chunk_size):
    chunk = ints[i:i+chunk_size]
    # process chunk of size <= chunk_size


@AnnaVopureta`chunk`对于最后一批元素将具有1、2或3个元素。请参阅有关为什么[切片索引可能超出范围]的问题(/sf/ask/17360801/)。

4> Markus Jarde..:
import itertools
def chunks(iterable,size):
    it = iter(iterable)
    chunk = tuple(itertools.islice(it,size))
    while chunk:
        yield chunk
        chunk = tuple(itertools.islice(it,size))

# though this will throw ValueError if the length of ints
# isn't a multiple of four:
for x1,x2,x3,x4 in chunks(ints,4):
    foo += x1 + x2 + x3 + x4

for chunk in chunks(ints,4):
    foo += sum(chunk)

其他方式:

import itertools
def chunks2(iterable,size,filler=None):
    it = itertools.chain(iterable,itertools.repeat(filler,size-1))
    chunk = tuple(itertools.islice(it,size))
    while len(chunk) == size:
        yield chunk
        chunk = tuple(itertools.islice(it,size))

# x2, x3 and x4 could get the value 0 if the length is not
# a multiple of 4.
for x1,x2,x3,x4 in chunks2(ints,4,0):
    foo += x1 + x2 + x3 + x4


对于这么简单的东西来说,它是相当漫长而笨拙的,根本不是很py.我更喜欢S. Lott的版本
@zenazn:这将适用于生成器实例,切片不会
+1用于使用生成器,在所有建议的解决方案中都像最“ pythonic”的接缝

5> Pedro Henriq..:
from itertools import izip_longest

def chunker(iterable, chunksize, filler):
    return izip_longest(*[iter(iterable)]*chunksize, fillvalue=filler)



6> bcoughlan..:

我需要一个也适用于集合和生成器的解决方案.我无法想出任何非常简短的东西,但它至少是可读的.

def chunker(seq, size):
    res = []
    for el in seq:
        res.append(el)
        if len(res) == size:
            yield res
            res = []
    if res:
        yield res

列表:

>>> list(chunker([i for i in range(10)], 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

组:

>>> list(chunker(set([i for i in range(10)]), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

发电机:

>>> list(chunker((i for i in range(10)), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]



7> rhettg..:

这个问题的理想解决方案适用于迭代器(不仅仅是序列).它也应该很快.

这是itertools文档提供的解决方案:

def grouper(n, iterable, fillvalue=None):
    #"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.izip_longest(fillvalue=fillvalue, *args)

%timeit在我的mac书籍空气中使用ipython ,我得到每循环47.5 us.

但是,这对我来说真的不起作用,因为结果被填充为偶数组.没有填充的解决方案稍微复杂一些.最天真的解决方案可能是:

def grouper(size, iterable):
    i = iter(iterable)
    while True:
        out = []
        try:
            for _ in range(size):
                out.append(i.next())
        except StopIteration:
            yield out
            break

        yield out

简单,但很慢:每循环693 us

我可以提出的最佳解决方案islice用于内循环:

def grouper(size, iterable):
    it = iter(iterable)
    while True:
        group = tuple(itertools.islice(it, None, size))
        if not group:
            break
        yield group

使用相同的数据集,我得到每个循环305 us.

无法以更快的速度获得纯粹的解决方案,我提供了以下解决方案,并提出了一个重要的警告:如果输入数据中包含实例,filldata则可能会得到错误的答案.

def grouper(n, iterable, fillvalue=None):
    #"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    for i in itertools.izip_longest(fillvalue=fillvalue, *args):
        if tuple(i)[-1] == fillvalue:
            yield tuple(v for v in i if v != fillvalue)
        else:
            yield i

我真的不喜欢这个答案,但速度要快得多.每循环124 us



8> kriss..:

与其他提案类似,但不完全相同,我喜欢这样做,因为它简单易读:

it = iter([1, 2, 3, 4, 5, 6, 7, 8, 9])
for chunk in zip(it, it, it, it):
    print chunk

>>> (1, 2, 3, 4)
>>> (5, 6, 7, 8)

这样你就不会获得最后的部分块.如果你想获得(9, None, None, None)的最后一个块,只需使用izip_longestitertools.



9> jfs..:

由于没有人提到它,所以这里有一个zip()解决方案:

>>> def chunker(iterable, chunksize):
...     return zip(*[iter(iterable)]*chunksize)

仅当序列的长度始终可被块大小整除,或者如果您不关心尾随的块时,它才起作用。

例:

>>> s = '1234567890'
>>> chunker(s, 3)
[('1', '2', '3'), ('4', '5', '6'), ('7', '8', '9')]
>>> chunker(s, 4)
[('1', '2', '3', '4'), ('5', '6', '7', '8')]
>>> chunker(s, 5)
[('1', '2', '3', '4', '5'), ('6', '7', '8', '9', '0')]

或使用itertools.izip返回迭代器而不是列表:

>>> from itertools import izip
>>> def chunker(iterable, chunksize):
...     return izip(*[iter(iterable)]*chunksize)

可以使用@ ?????????的答案来固定填充:

>>> from itertools import chain, izip, repeat
>>> def chunker(iterable, chunksize, fillvalue=None):
...     it   = chain(iterable, repeat(fillvalue, chunksize-1))
...     args = [it] * chunksize
...     return izip(*args)



10> catwell..:

使用map()而不是zip()修复了JF Sebastian的答案中的填充问题:

>>> def chunker(iterable, chunksize):
...   return map(None,*[iter(iterable)]*chunksize)

例:

>>> s = '1234567890'
>>> chunker(s, 3)
[('1', '2', '3'), ('4', '5', '6'), ('7', '8', '9'), ('0', None, None)]
>>> chunker(s, 4)
[('1', '2', '3', '4'), ('5', '6', '7', '8'), ('9', '0', None, None)]
>>> chunker(s, 5)
[('1', '2', '3', '4', '5'), ('6', '7', '8', '9', '0')]

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有