两个列表中的两个值,简化代码

时间:2015-02-20 03:49:02

标签: python

我有两个列表,我想比较每个列表中的值以查看差异是否在某个范围内,并返回每个列表中相同值的数量。这是我的代码第一版:

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,答案是错误的。所以我想知道第一版是否有更简单,更有效的代码,我有大量的数据需要处理。谢谢!

4 个答案:

答案 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),其中mn是列表的长度。


如果您需要更高效的算法,可以使用排序数据结构(如二叉树或排序列表)来实现更好的查找。

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的每个元素进行比较,但第二个元素仅对mn的相应元素进行成对比较,停止当较短的列表用完元素时。通过打印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的答案是我最喜欢的。 :)