写清单理解更好

时间:2017-09-26 15:48:05

标签: python list-comprehension

有没有办法写这个列表理解

moves = [m for m in moves if m[0] in range(8) and m[1] in range(8)]

以更好/更有效的方式?

moves是元组列表,只应包含0-7

中的值

它应该包含的元组:(0,0),(0,1)....(7,7)

元组它不应该包含:(-1,0),(0,-2),(8,3)......

4 个答案:

答案 0 :(得分:2)

尝试

moves = [m for m in moves if 0 <= m[0] <= 7 and 0 <= m[1] <= 7]

答案 1 :(得分:2)

您可以使用all来避免冗余:

moves = [m for m in moves if all(0 <= x < 8 for x in m)]

答案 2 :(得分:1)

不知道moves ...

中已有的内容

这应该稍微清理一下代码......

r = range(8)

moves = [m for m in moves if m[0] in r and m[1] in r]

@schwobaseggl指出的替代选项是使用all()函数:

moves = [m for m in moves if all(x in r for x in m)]

如果你想让事情移动得快一点,那么通过简单地测试两点之间的包含来消除函数调用和与范围相关的生成器过程将节省一些时间......

moves = [m for m in moves if all(0 <= x < 8 for x in m)]

但是将范围转换为集合可能会节省更多时间。如果你真的需要加快速度,应该进行更复杂的检查。

使用范围

In [7]: %%timeit moves = [(-1, 0), (2, 3), (-9, 0)]; r = range(8)
   ...: moves = [m for m in moves if all(x in r for x in m)]
   ...:
The slowest run took 6.65 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 978 ns per loop

使用两个端点

In [8]: %%timeit moves = [(-1, 0), (2, 3), (-9, 0)]; r = range(8)
   ...: moves =[m for m in moves if all(0 <= x < 8 for x in m)]
   ...:
   ...:
The slowest run took 7.31 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 768 ns per loop

使用SET

In [9]: %%timeit moves = [(-1, 0), (2, 3), (-9, 0)]; r = set(range(8))
   ...: moves =[m for m in moves if all(x in r for x in m)]
   ...:
   ...:
The slowest run took 7.25 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 763 ns per loop

答案 3 :(得分:0)

收集上面的一些优秀建议,我已经运行了一些基准

import random

N = 1000
R = 50

# generating pseudo-random input
random.seed(0)
moves = [tuple(random.randint(-R, R) for i in range(2)) for _ in range(N)]

@ A.Bau(原始问题)

%timeit [m for m in moves if m[0] in range(8) and m[1] in range(8)]
340 µs ± 1.73 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

@schwobaseggl

%timeit [m for m in moves if all(0 <= x < 8 for x in m)]
583 µs ± 2.62 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

@ user6731765

%timeit [m for m in moves if 0 <= m[0] <= 7 and 0 <= m[1] <= 7]
77.2 µs ± 251 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

@E。 Ducateme / 1

r = range(8)
%timeit [m for m in moves if m[0] in r and m[1] in r]
120 µs ± 509 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

@E。 Ducateme / 2

r = range(8)
%timeit [m for m in moves if all(x in r for x in m)]
630 µs ± 5.77 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

@E。 Ducateme / 3

r = set(range(8))
%timeit [m for m in moves if m[0] in r and m[1] in r]
62 µs ± 303 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

@wim

valid_moves = {(x, y) for x in range(8) for y in range(8)}
%timeit [m for m in moves if m in valid_moves]
60.2 µs ± 143 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

@wim(即使m不可删除也已修改为有效,例如列表)

valid_moves = {(x, y) for x in range(8) for y in range(8)}
%timeit [m for m in moves if tuple(m) in valid_moves]
220 µs ± 9.53 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

@wim(已修改为即使m不可用也无法工作 - 没有tuple来电)

valid_moves = {(x, y) for x in range(8) for y in range(8)}
%timeit [(x, y) for x, y in moves if (x, y) in valid_moves]
92.7 µs ± 1.53 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

摘要

基于这些测试,应该能够更明智地选择针对特定问题的选择。

如果m中的元素数量始终是固定的,那么@ wim的方法是最快且可读的方法之一:

valid_moves = {(x, y) for x in range(8) for y in range(8)}
moves = [m for m in moves if m in valid_moves]

如果m的元素数量未知(最终可变),那么@ E.Ducateme的方法可以提供相当快的结果和良好的可读性:

r = set(range(8))
moves = [m for m in moves if all(x in r for x in m)]

但如果您真的关心原始速度,那么您应该最终使用您的输入测试方法。