目前,您在檢查IP之前將所有網絡加載到內存中,但您並不需要這樣做,只需遍歷讀取器而不是將其轉換爲列表即可。
相反,我會加載所有的IP地址來檢查列表並對它們進行排序。然後,可以使用bisect
從對象時間內的單個網絡中的列表中獲取所有IP,因此,您將擁有O(m*log(n))
而不是O(m*n)
,並加上排序地址列表的成本。
應類似於此*:
from bisect import bisect_left, bisect_right
def find_ips_in_network(network, sorted_ips):
first = netaddr.IPAddress(network.first)
last = netaddr.IPAddress(network.last)
first_idx = bisect_left(sorted_ips, first)
last_idx = bisect_right(sorted_ips, last)
return sorted_ips[first_idx:last_idx]
sorted_ips = sorted(...) # load ips as sorted list of netaddr.IPAddress
found_networks = dict()
# or collections.defaultdict(list) if you want all networks
with open(r"file.csv", 'rb') as f:
reader = csv.reader(f)
for row in reader:
network = netaddr.IPNetwork(row[0])
for ip in find_ips_in_network(network, sorted_ips):
found_networks[ip] = row
# or found_networks[ip].append(row) if using defaultdict
for ip in sorted_ips:
if ip in found_networks:
print ip, "found in:", found_networks[ip]
*免責聲明:正確性不能保證
編輯:小優化:由於第一地址的指數的平均值,它可以用來限制爲最後一個索引搜索時下界:
last_idx = bisect_right(sorted_ips, last, first_index)
說明:bisect_left
和bisect_right
使用binary search在已排序列表中搜索給定值,並返回必須插入值的索引以維護列表的排序。 bisect_left
和bisect_right
之間的差值是其中值已經在列表中的情況(一次或多次),bisect_left
將返回第一次匹配的索引,bisect_right
最後一次+1的索引。
因此,在這種情況下:
first_idx = bisect_left(sorted_ips, first)
將從sorted_ips
比first
大於或等於返回第一個ip地址的索引,
last_idx = bisect_right(sorted_ips, last, first_idx)
最後一個ip地址後返回索引一個小或等於last
。 我們知道first <= last
,因此fist_idx
必須是<= last_idx
,因此第二個搜索的下限可以限制在first_idx
。
這意味着片段sorted_ips[first_idx:last_idx]
包含列表中的所有IP,first <= ip <= last
。如果列表中沒有地址相等,或者first
和last
之間的地址相同,則兩個索引將相同,返回空列表。
由於二進制搜索的最差情況下性能爲O(log(n))
,因此查找列表中的哪些IP位於網絡中,然後檢查所有IP的所有網絡,特別是如果要檢查的IP列表非常大。
我會試試這個,並報告它是否更快。感謝您回答 – Con7e
「return sorted_ips [first_idx:last_idx]」總是返回我最初用來在數據庫中搜索的「sorted_IPs」列表。爲什麼是這樣?我對數據庫中的信息感興趣,而不是我自己的列表。你能幫我嗎? – Con7e
該函數應返回給定網絡中列表中的所有ips。根據我的理解,您正在嘗試查找IP列表,以確定它們是否位於您csv的某個網絡中,是正確還是誤解了某些內容?這個解決方案可以解決這個問題,並檢查是否有給定IP的所有網絡。 – mata