我有两个列表,我想比较每个列表中的值以查看差异是否在某个范围内,并返回每个列表中相同值的数量。这是我的代码第一版:
m = [1,3,5,7]
n = [1,4,7,9,5,6,34,52]
k=0
for i in xrange(0, len(m)):
for j in xrange(0, len(n)):
if abs(m[i] - n[j]) <=0.5:
k+=1
else:
continue
输出为3.我也尝试了第二版:
for i, j in zip(m,n):
if abs(i - j) <=0.5:
t+=1
else:
continue
输出为1,答案是错误的。所以我想知道第一版是否有更简单,更有效的代码,我有大量的数据需要处理。谢谢!
答案 0 :(得分:5)
您可以做的第一件事是删除else: continue
,因为它不会添加任何内容。此外,您可以直接使用for a in m
来避免迭代范围和索引。
如果您想更有效地编写它,可以使用itertools。
import itertools
m = [1,3,5,7]
n = [1,4,7,9,5,6,34,52]
k = sum(abs(a - b) <= 0.5 for a, b in itertools.product(m, n))
此(和您的解决方案)的运行时为O(m * n)
,其中m
和n
是列表的长度。
如果您需要更高效的算法,可以使用排序数据结构(如二叉树或排序列表)来实现更好的查找。
import bisect
m = [1,3,5,7]
n = [1,4,7,9,5,6,34,52]
n.sort()
k = 0
for a in m:
i = bisect.bisect_left(n, a - 0.5)
j = bisect.bisect_right(n, a + 0.5)
k += j - i
运行时为O((m + n) * log n)
。那个n * log n
用于排序,m * log n
用于查找。因此,您希望将n
设为较短的列表。
答案 1 :(得分:3)
您的第一个版本的更多pythonic版本:
ms = [1, 3, 5, 7]
ns = [1, 4, 7, 9, 5, 6, 34, 52]
k = 0
for m in ms:
for n in ns:
if abs(m - n) <= 0.5:
k += 1
我认为它不会运行得更快,但它更简单(更易读)。
答案 2 :(得分:1)
直接迭代列表而不是迭代范围对象以获取索引值更简单,也可能稍快一些。您已经在第二个版本中执行了此操作,但是您没有使用该zip()调用构建所有可能的对。这是对您的第一个版本的修改:
m = [1,3,5,7]
n = [1,4,7,9,5,6,34,52]
k=0
for x in m:
for y in n:
if abs(x - y) <=0.5:
k+=1
你不需要else: continue
部分,它在循环结束时什么都不做,所以我把它留了出来。
如果要探索生成器表达式来执行此操作,可以使用:
k = sum(sum( abs(x-y) <= 0.5 for y in n) for x in m)
只使用核心语言并且没有导入,这应该能够合理地运行。
答案 3 :(得分:1)
您的两个代码段正在执行两个不同的操作。第一个是将n
的每个元素与m
的每个元素进行比较,但第二个元素仅对m
和n
的相应元素进行成对比较,停止当较短的列表用完元素时。通过打印zip
:
>>> m = [1,3,5,7]
>>> n = [1,4,7,9,5,6,34,52]
>>> zip(m,n)
[(1, 1), (3, 4), (5, 7), (7, 9)]
pawelswiecki发布了更多Pythonic版本的第一个片段。通常,除非您确实需要索引,否则直接迭代容器而不是使用索引循环更好。即便如此,使用enumerate()
来生成索引比使用xrange(len(m))
更加Pythonic。例如
>>> for i, v in enumerate(m):
... print i, v
...
0 1
1 3
2 5
3 7
根据经验,如果你发现自己写for i in xrange(len(m))
,那么可能是更好的方法。 :)
William Gaul提出了一个很好的建议:如果您的列表已经排序,一旦绝对差值超过0.5的阈值,您就可以break
退出内循环。但是,Paul Draper使用bisect
的答案是我最喜欢的。 :)