有没有更好的方法来迭代两个列表来查找python中的项之间的关系?

我模拟了一个ip列表和一个子网dict作为输入:

# ip address list
ip_list = [
'192.168.1.151', '192.168.10.191', '192.168.6.127', 
'192.168.2.227', '192.168.2.5', '192.168.3.237', 
'192.168.6.188', '192.168.7.209', '192.168.9.10',
# Edited: add some /28, /16 case
'192.168.12.39', '192.168.12.58', '10.63.11.1', '10.63.102.69',
]

# subnet dict
netsets = {
'192.168.1.0/24': 'subnet-A',     # {subnet: subnet's name} 
'192.168.10.0/24': 'subnet-B', 
'192.168.2.0/24': 'subnet-C', 
'192.168.3.0/24': 'subnet-C',
'192.168.6.0/24': 'subnet-D', 
'192.168.7.0/24': 'subnet-D', 
'192.168.9.0/24': 'subnet-E',
# Edited: add some /28, /16 case
'192.168.12.32/28': 'subnet-F',
'192.168.12.48/28': 'subnet-G',
'10.63.0.0/16': 'subnet-I',
}

然后ip_list中的每个ip地址都需要找到子网的名称.

我们假设每个IP地址都可以在netsets中找到相应的子网.

像这样的输出:

192.168.1.151   subnet-A
192.168.10.191  subnet-B
192.168.6.127   subnet-D
192.168.2.227   subnet-C
192.168.2.5     subnet-C
192.168.3.237   subnet-C
192.168.6.188   subnet-D
192.168.7.209   subnet-D
192.168.9.10    subnet-E
# add some /28, /16 case
192.168.12.39   subnet-F
192.168.12.58   subnet-G
10.63.11.1      subnet-I
10.63.102.69    subnet-I

我用netaddr来计算CIDR,这是我的代码:

from netaddr import IPAddress, IPNetwork

def netaddr_test(ips, netsets):
    for ip in ips:
        for subnet, name in netsets.iteritems():
            if IPAddress(ip) in IPNetwork(subnet):
                print ip, '\t',  name
                break

netaddr_test(ip_list, netsets)

但是这段代码太慢了,迭代太多了.时间的复杂性是O(n ** 2).

一旦我们有成千上万的ip迭代,这段代码花费了太多时间.

有没有更好的方法来解决这个问题?

最佳答案 我建议使用经过特别优化的
intervaltree模块来快速搜索.因此,任务可以在O(m * log n)时间内求解.例如:

   from intervaltree import Interval, IntervalTree
   from ipaddress import ip_network, ip_address

   # build nets tree
   netstree = IntervalTree(
                           Interval(
                                    ip_network(net).network_address, 
                                    ip_network(net).broadcast_address, 
                                    name
                                   ) 
                          for 
                          net, name 
                          in 
                          netsets.items()
                         )

   # Now you may check ip intervals     
   for i in ip_list:
       ip = ip_address(i)
       nets = netstree[ip]
       if nets:   # set is not empty
            netdata = list(nets)[0]
            print(netdata.data)
            # prints 'subnet-E'
点赞