目前,您在检查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