【问题标题】:Optimize three nested for-loops iterating through 2 dataframes of IP addresses?优化三个嵌套的 for 循环迭代 2 个 IP 地址数据帧?
【发布时间】:2018-10-04 01:45:49
【问题描述】:

我有 2 个 CSV 文件。 一个带有主机名和 IP。 第二个带有 IP 信息(网络掩码、Cidr、子网名称等)

我目前有如下情况。

for i, ipAddress in CSV1:
       for j, ipNetwork in CSV2:
             if ipAddress in ipNetwork:
                  append ipNetwork['Subnet Name']

不幸的是,第一个 csv 有 9000 个 IP,第二个列表有 30'000 个子网。这需要花费大量时间来迭代。我知道这是一种糟糕的实现方式,但我知道我总是可以改进的。

谁能告诉我如何更好地解决这个问题?如何搜索和比较每个元素中的元素以缩短此脚本的运行时间?

这是样本数据

[CSV 1 - Sample IP]

IP Address
144.196.86.89
56.144.25.138
3.16.101.238
123.18.128.50
19.22.2.124
78.88.241.163
144.44.200.20
27.215.172.218
124.90.163.19

[CSV 2 - Sample Subnet Information]

address netmask Company Subnet Name Compartment Type    cidr
10.2.1.0    255.255.255.0   UPS UPS Site 1  Desktop 10.2.1.0/24
10.2.2.0    255.255.255.0   UPS UPS Site 2  Desktop 10.2.2.0/24
10.2.3.0    255.255.255.0   UPS UPS Site 3  Desktop 10.2.3.0/24
10.2.4.0    255.255.255.0   UPS UPS Site 4  Desktop 10.2.4.0/24
10.2.5.0    255.255.255.0   UPS UPS Site 5  Desktop 10.2.5.0/24
10.2.6.0    255.255.255.0   UPS UPS Site 6  Desktop 10.2.6.0/24
10.2.7.0    255.255.255.0   UPS UPS Site 7  Desktop 10.2.7.0/24
10.2.8.0    255.255.255.0   UPS UPS Site 8  Desktop 10.2.8.0/24
10.2.10.0   255.255.254.0   UPS UPS Site 9  Desktop 10.2.10.0/23
10.2.12.0   255.255.255.0   UPS UPS Site 10 Desktop 10.2.12.0/24
10.2.13.0   255.255.255.0   UPS UPS Site 11 Desktop 10.2.13.0/24

【问题讨论】:

  • 你能分享一些数据吗?请参阅minimal reproducible example
  • @jpp 我不明白你为什么不赞成他的问题。我认为它有足够的信息来保证解决方案或至少是想法
  • 所以我推荐的一个建议是将 IP 地址和子网(假设它们都表示为字符串)转换为整数或字节。原因是字符串是不可变的,字符串比较是一项昂贵的操作。你也许能得到一些想法here
  • 主要问题是我不知道为什么你现在的方法这么慢。你在使用原生 Python open 吗? csv 模块? pandas?我们如何知道我们提供的解决方案是否是您当前使用的慢速解决方案?
  • @Plisken,那么 CSV1 / CSV2 是什么?请提供 minimal reproducible example

标签: python python-3.x pandas csv ip-address


【解决方案1】:

1) 显然它很慢,因为 OP 有三个嵌套循环:CSV1 文件上的两级嵌套迭代 (i, j),然后是 ipNetwork 上的迭代.你应该避免像瘟疫那样深嵌套。

要测试 CSV1 中的成员资格,请在 CSV1 上进行第一次迭代以读取所有 ip,并存储为 set

ips = [line[0] for line in CSV1.readlines()] # or whatever, using csv.reader
ips = set(ips)

事实上,最新版本的 Python 允许您直接生成集合(这称为 生成器表达式

ips = set(line[0] for line in CSV1.readlines())

现在您根本不需要 j 迭代,因为您使用的是 set。您只需使用if ip in ... 测试会员资格即可 所以我们已经消除了你的三个嵌套循环之一。也许两个。

2) 另外要在测试 ip in ipNetworks... 时获得性能提升,您可以使用正则表达式和/或分层 ipAddress 类,例如允许将ipAddress('157.55.130')ipAddress('157.55.*.*) 进行比较。在比较 IP 时查看 SO 上的许多现有重复项。您可以允许使用通配符 * 和/或 xxx。 如果您使用通配符并合并相邻地址,您应该能够将 CSV1 和 ipNetwork 长度分别压缩到 9K;30K 以下。

查看许多现有的 SO 问题,例如: 1.使用正则表达式Python: Efficient way to compare ip addresses in a csv file 1.使用自定义类Compare IP List to another IP List or IP Range 1.与范围Checking if IP address lies within a given range比较

【讨论】:

【解决方案2】:

这里有一些很棒的建议,它给了我很多东西。

我最终做的是按 IP 对两个列表进行排序。一旦我比较了 IP 的排序列表并在 CIDR 列表中查找 IP 网络,我会将其设置为临时变量。许多 IP 是连续的,因此接下来的几个 IP 很可能也在临时范围内。

然后我基本上将搜索范围缩小到找到的 CIDR 的索引。所以每次迭代后,我的 CIDR 列表搜索量都会减少。

它可能不是很漂亮或最优化,但它确实有效。

稍等一下,我会附上它的样本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-07
    • 1970-01-01
    • 2012-01-27
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多