Python:比较两个整数列表的最有效方法

时间:2013-10-09 21:11:59

标签: python performance list comparison

我正在尝试比较Python 2.6中的两个整数列表,每个整数列表大小相同。我需要的比较是将列表1中的第一项与列表2中的第一项进行比较,将列表1中的第二项与列表2中的第二项进行比较,依此类推,如果所有列表项都跟随,则返回结果相同的比较标准。它应该表现如下:

list1 = [1,1,1,1]
list2 = [2,1,2,3]
compare(list1,list2) 
# returns a "list 1 is <= list 2" response.

list1 = [4,1,4,3]
list2 = [2,1,2,3]
compare(list1,list2) 
# returns a "list 1 is >= list 2" response.

list1 = [3,2,3,2]
list2 = [1,4,1,4]
compare(list1,list2) 
# returns None— some items in list1 > list2, and some items in list2 > list1.

我想我可以编写类似下面的代码,但我不知道它是否最有效。我的程序将调用这个方法很多,所以我想尽可能地简化这个。

def compare(list1,list2):
    gt_found = 0
    lt_found = 0
    for x in range(len(list1)):
        if list1[x] > list2[x]:
            gt_found += 1
        elif list1[x] < list2[x]:        
            lt_found += 1
        if gt_found > 0 and lt_found > 0:
            return None   #(some items >, some items <)
    if gt_found > 0:
        return 1          #(list1 >= list2)
    if lt_found > 0:
        return -1         #(list1 <= list2)
    return 0              #(list1 == list2)

它是否已经达到了它的好处(n的大O),或者是否有更快的方法(或者使用系统功能的方式)?

澄清:我希望返回“无”的情况最常发生,所以这很重要。

3 个答案:

答案 0 :(得分:5)

您熟悉精彩的zip功能吗?

import itertools

def compare(xs, ys):
  all_less = True
  all_greater = True

  for x, y in itertools.izip(xs, ys):
    if not all_less and not all_greater:
      return None
    if x > y:
      all_less = False
    elif x < y:
      all_greater = False

  if all_less:
    return "list 1 is <= list 2"
  elif all_greater:
    return "list 1 is >= list 2"
  return None  # all_greater might be set False on final iteration

Zip在这种情况下需要两个列表(xsys,但可以随意调用它们)并为一系列元组创建一个迭代器。

izip([1,2,3,4], [4,3,2,1]) == [(1,4), (2,3), (3,2), (4,1)]

通过这种方式,您可以同时迭代两个列表并串联比较每个值。时间复杂度应为O(n),其中n是列表的大小。

如果未满足&gt; =或&lt; =条件,它将提前返回。

更新

正如 James Matta 所指出的那样,itertools.izip的性能优于Python 2中的标准zip。在Python 3中并非如此,其中标准{{1}按照旧版本zip的方式工作。

答案 1 :(得分:5)

您可以考虑基于numpy的矢量化比较。

import numpy as np

a = [1,1,1,2]
b = [2,2,4,3]

all_larger = np.all(np.asarray(b) > np.asarray(a))  # true if b > a holds elementwise

print all_larger

        True

显然,你可以设计得到你的答案。

all_larger = lambda b,a : np.all(np.asarray(b) > np.asarray(a))

if all_larger(b,a):
       print "b > a"
elif all_larger(a,b):
       print "a > b"

else
       print "nothing!"

可以完成<, >, <=, >=,等每种类型的比较。

答案 2 :(得分:0)

对于对这两种方法的表现感兴趣的人,我将迭代方法命名为“龟”&#39;和numpy方法&#39; hare&#39;,并使用下面的代码进行测试。

起初,“龟”&#39;赢了[.009s [T] vs .033s [H]],但我检查了一下,发现asarray()被调用的频率超过了它需要的频率。通过这个修复,&#39;野兔&#39;又赢了,[。009s [T] vs .006s [H]]。

数据在这里:http://tny.cz/64d6e5dc
它由28行约950个元素组成。其中四行总是&gt; =所有其他行。

看看性能如何适用于更大的数据集可能会很有趣。

import itertools, operator, math
import cProfile
import numpy as np

data = #SEE PASTEBIN

def tortoise(xs, ys):
    all_less = True
    all_greater = True

    for x, y in zip(xs, ys):
        if not all_less and not all_greater:
          return None
        if x > y:
          all_less = False
        elif x < y:
          all_greater = False

    if all_greater and all_less:
        return 0
    if all_greater:
        return 1
    if all_less:
        return -1
    return None  # all_greater might be set False on final iteration


hare = lambda b,a : np.all(b >= a)

def find_uniques_tortoise():
    include_list = range(len(data))
    current_list_index = 0
    while current_list_index < len(data):
        if current_list_index not in include_list:
            current_list_index += 1
            continue
        for x in range(current_list_index+1,len(data)):
            if x not in include_list:
                continue
            result = tortoise(data[current_list_index], data[x])
            if result is None: #no comparison
                continue 
        elif result == 1 or result == 0: # this one beats the other one
            include_list.remove(x)
            continue
        elif result == -1: #the other one beats this one
            include_list.remove(current_list_index)
            break
    current_list_index +=1
return include_list

def find_uniques_hare():
    include_list = range(len(data))
    current_list_index = 0
    #do all asarray()s beforehand for max efficiency
    for x in range(len(data)): 
        data[x] = np.asarray(data[x])
    while current_list_index < len(data):
        if current_list_index not in include_list:
            current_list_index += 1
            continue
        for x in range(current_list_index+1,len(data)):
            if x not in include_list:
                continue
            if hare(data[current_list_index], data[x]): # this one beats the other one, or it's a tie
                include_list.remove(x)
            #   print x
                continue
            elif hare(data[x], data[current_list_index]): #the other one beats this one
                include_list.remove(current_list_index)
            #   print current_list_index
                break
            else: #no comparison
                continue
        current_list_index +=1
    return include_list             



cProfile.run('find_uniques_tortoise()')
cProfile.run('find_uniques_hare()')

print find_uniques_tortoise()
print   
print find_uniques_hare()       
相关问题