Python 来自单个列表的对

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4628290/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 16:36:36  来源:igfitidea点击:

Pairs from single list

pythonlistzipsliceidioms

提问by Apalala

Often enough, I've found the need to process a list by pairs. I was wondering which would be the pythonic and efficient way to do it, and found this on Google:

通常,我发现需要成对处理列表。我想知道哪种 Pythonic 和有效的方法可以做到这一点,并在 Google 上找到了这个:

pairs = zip(t[::2], t[1::2])

I thought that was pythonic enough, but after a recent discussion involving idioms versus efficiency, I decided to do some tests:

我认为这已经足够 Pythonic 了,但在最近讨论了习惯用法与效率之后,我决定做一些测试:

import time
from itertools import islice, izip

def pairs_1(t):
    return zip(t[::2], t[1::2]) 

def pairs_2(t):
    return izip(t[::2], t[1::2]) 

def pairs_3(t):
    return izip(islice(t,None,None,2), islice(t,1,None,2))

A = range(10000)
B = xrange(len(A))

def pairs_4(t):
    # ignore value of t!
    t = B
    return izip(islice(t,None,None,2), islice(t,1,None,2))

for f in pairs_1, pairs_2, pairs_3, pairs_4:
    # time the pairing
    s = time.time()
    for i in range(1000):
        p = f(A)
    t1 = time.time() - s

    # time using the pairs
    s = time.time()
    for i in range(1000):
        p = f(A)
        for a, b in p:
            pass
    t2 = time.time() - s
    print t1, t2, t2-t1

These were the results on my computer:

这些是我电脑上的结果:

1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578

If I'm interpreting them correctly, that should mean that the implementation of lists, list indexing, and list slicing in Python is very efficient. It's a result both comforting and unexpected.

如果我正确地解释了它们,那应该意味着在 Python 中实现列表、列表索引和列表切片是非常有效的。这是一个既令人欣慰又出乎意料的结果。

Is there another, "better" way of traversing a list in pairs?

还有另一种“更好”的成对遍历列表的方法吗?

Note that if the list has an odd number of elements then the last one will not be in any of the pairs.

请注意,如果列表具有奇数个元素,则最后一个将不在任何对中。

Which would be the right way to ensure that all elements are included?

哪个是确保包含所有元素的正确方法?

I added these two suggestions from the answers to the tests:

我从测试的答案中添加了这两个建议:

def pairwise(t):
    it = iter(t)
    return izip(it, it)

def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

These are the results:

这些是结果:

0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176

Results so far

到目前为止的结果

Most pythonic and very efficient:

最pythonic且非常高效:

pairs = izip(t[::2], t[1::2])

Most efficient and very pythonic:

最高效且非常 Pythonic:

pairs = izip(*[iter(t)]*2)

It took me a moment to grok that the first answer uses two iterators while the second uses a single one.

我花了一点时间才明白第一个答案使用了两个迭代器,而第二个答案使用了一个迭代器。

To deal with sequences with an odd number of elements, the suggestion has been to augment the original sequence adding one element (None) that gets paired with the previous last element, something that can be achieved with itertools.izip_longest().

为了处理具有奇数个元素的序列,建议增加原始序列添加一个元素 ( None) 与前一个最后一个元素配对,这可以通过itertools.izip_longest().

Finally

最后

Note that, in Python 3.x, zip()behaves as itertools.izip(), and itertools.izip()is gone.

请注意,在 Python 3.x 中,zip()表现为itertools.izip(), 并且itertools.izip()消失了。

采纳答案by Jochen Ritzel

My favorite way to do it:

我最喜欢的做法:

from itertools import izip

def pairwise(t):
    it = iter(t)
    return izip(it,it)

# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[it]*size)

When you want to pair all elements you obviously might need a fillvalue:

当您想要配对所有元素时,您显然可能需要一个填充值:

from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
    it = iter(t)
    return izip_longest(*[it]*size, fillvalue=fillvalue)

回答by Aaron Digulla

Is there another, "better" way of traversing a list in pairs?

还有另一种“更好”的成对遍历列表的方法吗?

I can't say for sure but I doubt it: Any other traversal would include more Python code which has to be interpreted. The built-in functions like zip() are written in C which is much faster.

我不能肯定,但我对此表示怀疑:任何其他遍历都会包含更多必须解释的 Python 代码。像 zip() 这样的内置函数是用 C 编写的,速度要快得多。

Which would be the right way to ensure that all elements are included?

哪个是确保包含所有元素的正确方法?

Check the length of the list and if it's odd (len(list) & 1 == 1), copy the list and append an item.

检查列表的长度,如果它是奇数 ( len(list) & 1 == 1),则复制列表并附加一个项目。

回答by Tim Pietzcker

I'd say that your initial solution pairs = zip(t[::2], t[1::2])is the best one because it is easiest to read (and in Python 3, zipautomatically returns an iterator instead of a list).

我会说你的初始解决方案pairs = zip(t[::2], t[1::2])是最好的,因为它最容易阅读(并且在 Python 3 中,zip自动返回一个迭代器而不是一个列表)。

To ensure that all elements are included, you could simply extend the list by None.

为确保包含所有元素,您可以简单地将列表扩展None.

Then, if the list has an odd number of elements, the last pair will be (item, None).

然后,如果列表有奇数个元素,最后一对将是(item, None)

>>> t = [1,2,3,4,5]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, None)]
>>> t = [1,2,3,4,5,6]
>>> t.append(None)
>>> zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]

回答by Tomasz Elendt

I start with small disclaimer - don't use the code below. It's not Pythonic at all, I wrote just for fun. It's similar to @THC4k pairwisefunction but it uses iterand lambdaclosures. It doesn't use itertoolsmodule and doesn't support fillvalue. I put it here because someone might find it interesting:

我从小的免责声明开始 - 不要使用下面的代码。它根本不是 Pythonic,我只是为了好玩而写的。它类似于@THC4kpairwise函数,但它使用iterlambda闭包。它不使用itertools模块,也不支持fillvalue. 我把它放在这里是因为有人可能会觉得它很有趣:

pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)

回答by Pat

As far as most pythonic goes, I'd say the recipes supplied in the python source docs(some of which look a lot like the answers that @JochenRitzel provided) is probably your best bet ;)

就大多数 pythonic 而言,我想说python 源文档中提供食谱(其中一些看起来很像@JochenRitzel 提供的答案)可能是你最好的选择;)

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

回答by Diarmuid O'Briain

>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
...     a = my_list.pop(0); b = my_list.pop(0)
...     my_pairs.append((a,b))
... 
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]

回答by Vlad Bezden

Here is an example of creating pairs/legs by using a generator. Generators are free from stack limits

这是使用生成器创建对/腿的示例。生成器不受堆栈限制

def pairwise(data):
    data = iter(data)
    begin = next(data)
    for end in data:
        yield begin, end
        begin = end

Example:

例子:

print(list(pairwise(range(10))))

Output:

输出:

[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]

And here is an example using zip function:

这是使用 zip 函数的示例:

def pairwise(data):
    return zip(data, data[1:])

Example:

例子:

print(list(pairwise(range(10))))

Output:

输出:

[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]