簡體   English   中英

在python中檢查一組數字中數字存在的最高效方法是什么

[英]What is the most performant way to check existance of a number in a set of numbers in python

所以我在這樣的列表中有一個python中的數字列表: [1,89,1221,1919,1920,10210,...]有幾千個數字,我想檢查我是否有變量。

我是這樣做的:

if i in mylist:

但這是最快的方式嗎?

一些進一步的規格:

  • 該列表沒有重復
  • 該列表僅包含整數
  • 如果提高性能,可以訂購列表
  • 該列表實際上可以是一個集合(所以沒有重復)
  • 列表可以是任何類型的集合

只有當您在此列表上進行多次查找時,轉換為set才有意義。 如果性能很重要,您應該測量從一開始就使用一個set (同時仍然插入元素)提供比列表更好的性能。 簡而言之,嘗試一些事情並衡量。

但是,僅僅因為創建新數據結構的開銷而轉換為僅用於單個成員資格測試的集合確實效率低下。

import random
import timeit

mylist = list(random.randint(1, 50000) for i in xrange(1000))
myset = set(mylist)

s = "1919 in mylist"
t = timeit.Timer(s, "from __main__ import mylist")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

s = "1919 in set(mylist)"
t = timeit.Timer(s, "from __main__ import mylist")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

結果如下:

1919 in mylist:22.81 usec/pass
1919 in set(mylist):65.42 usec/pass

一種方法是使用timeit模塊來測試各種方法。 例如,我掀起了以下代碼:

import array
import bisect
import random
import timeit

mylist = list(random.randint(1, 50000) for i in xrange(1000))
myset = set(mylist)
myarray = array.array('l', mylist)

s = "1919 in mylist"
t = timeit.Timer(s, "from __main__ import mylist")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

s = "1919 in myset"
t = timeit.Timer(s, "from __main__ import myset")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

s = "1919 in myarray"
t = timeit.Timer(s, "from __main__ import myarray")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

mysortedlist = sorted(mylist)
mysortedarray = array.array('l', mysortedlist)

s = "1919 in mysortedlist"
t = timeit.Timer(s, "from __main__ import mysortedlist")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

s = "1919 in mysortedarray"
t = timeit.Timer(s, "from __main__ import mysortedarray")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

def bisect_in(a, x):
    i = bisect.bisect_left(a, x)
    return (i != len(a) and a[i] == x)

s = "bisect_in(mysortedlist, 1919)"
t = timeit.Timer(s, "from __main__ import bisect_in, mysortedlist")
print s + ":%.2f usec/pass" % (1000000 * t.timeit(number = 100000)/100000)

我得到了以下結果:

1919 in mylist:73.89 usec/pass
1919 in myset:0.29 usec/pass
1919 in myarray:103.77 usec/pass
1919 in mysortedlist:75.12 usec/pass
1919 in mysortedarray:114.21 usec/pass
bisect_in(mysortedlist, 1919):4.17 usec/pass

它支持使用集合的其他人的爭用最快(在此測試代碼的假設下)。

轉換為一組,做in是最快的方法。

if i in set(mylist):

集合基本上是哈希表,查找是O(1)。

從列表中創建一個集合,與集合相交並檢查交集的大小?

如果您願意犧牲一些內存效率,可以構建一個查找表,其中列表索引是您要檢查的值。

原始清單:

   In [106]: %timeit i in myList
   10000 loops, best of 3: 21.3 us per loop

構建查找表:

   In [90]: lookup = [False for i in range( max(myList)+1 )]

   In [91]: for i in myList:
                lookup[i] = True

   In [92]: %timeit lookup[i]
   10000000 loops, best of 3: 50.7 ns per loop  

查找表比未排序列表快約400倍。

如果列表的最大值可接受地低,並且設置查找表的時間遠遠小於檢查變量是否在表中的所有時間,則此選項才真正可行。

有趣的是,使用Numpy數組時,查找表方法的速度要慢25%。 (但是構建查找表要快得多)

編輯:此方法的速度優於“i in set(myList)”因子2。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM