我有以下蛮力选项,可让我遍历各个点:

# [x1, y1, x2, y2, ..., xn, yn]
coords = [1, 1, 2, 2, 3, 3]
# The goal is to operate with (x, y) within for loop
for (x, y) in zip(coords[::2], coords[1::2]):
   # do something with (x, y) as a point


有更简洁/有效的方法吗?

最佳答案

coords-> items

简短答案

如果您想将项目按特定长度2分组,则

zip(items[::2], items[1::2])


就速度和清晰度而言,这是最好的折衷方案之一。
如果您负担得起额外的一行,则可以通过使用迭代器来提高效率(对于较大的输入,很多):

it = iter(items)
zip(it, it)


长答案

(编辑:添加了避免zip()的方法)

您可以通过多种方式实现这一目标。
为了方便起见,我将它们编写为可以进行基准测试的函数。
另外,我会将组的大小保留为参数n(在您的情况下为2

def grouping1(items, n=2):
    return zip(*tuple(items[i::n] for i in range(n)))


def grouping2(items, n=2):
    return zip(*tuple(itertools.islice(items, i, None, n) for i in range(n)))


def grouping3(items, n=2):
    for j in range(len(items) // n):
        yield items[j:j + n]


def grouping4(items, n=2):
    return zip(*([iter(items)] * n))


def grouping5(items, n=2):
    it = iter(items)
    while True:
        result = []
        for _ in range(n):
            try:
                tmp = next(it)
            except StopIteration:
                break
            else:
                result.append(tmp)
        if len(result) == n:
            yield result
        else:
            break


用相对简短的清单进行基准测试可以得出:

short = list(range(10))

%timeit [x for x in grouping1(short)]
# 1.33 µs ± 9.82 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit [x for x in grouping2(short)]
# 1.51 µs ± 16.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit [x for x in grouping3(short)]
# 1.14 µs ± 28.8 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit [x for x in grouping4(short)]
# 639 ns ± 7.56 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
%timeit [x for x in grouping5(short)]
# 3.37 µs ± 16.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


对于中型输入:

medium = list(range(1000))

%timeit [x for x in grouping1(medium)]
# 21.9 µs ± 466 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit [x for x in grouping2(medium)]
# 25.2 µs ± 257 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit [x for x in grouping3(medium)]
# 65.6 µs ± 233 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit [x for x in grouping4(medium)]
# 18.3 µs ± 114 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit [x for x in grouping5(medium)]
# 257 µs ± 2.88 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)


对于较大的输入:

large = list(range(1000000))

%timeit [x for x in grouping1(large)]
# 49.7 ms ± 840 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [x for x in grouping2(large)]
# 37.5 ms ± 42.4 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [x for x in grouping3(large)]
# 84.4 ms ± 736 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [x for x in grouping4(large)]
# 31.6 ms ± 85.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [x for x in grouping5(large)]
# 274 ms ± 2.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)


就效率而言,grouping4()似乎是最快的,紧随其后的是grouping1()grouping3()(取决于输入的大小)。

在您的情况下,grouping1()似乎是速度和清晰度之间的良好折衷,除非您愿意将其包装在函数中。

请注意,grouping4()要求您多次使用同一迭代器,并且:

zip(iter(items), iter(items))


将无法正常工作。

如果您想更好地控制不均匀分组,即len(items)不能被n整除,则可以从标准库中用zip替换itertools.zip_longest()

还请注意,grouping4()实际上是itertools official documentation中的grouper()配方。

09-12 15:41