Python中展平track_ip字典嵌套列表并保留IP元素逗号分隔
解决字典中嵌套列表展平问题(保留完整IP元素)
我需要构建一个track_ip字典,用source_ip作为键,对应的值是该源IP对应的所有destination_ip的列表(允许重复)。同时还要计算两个衍生列:time_since_last(同一源IP上次事件的间隔时间)和diff_destination_ip(当前目标IP是否与之前的不同)。但当前代码中因为初始值是字符串,后续追加时会生成嵌套列表,展平又会拆分IP字符,导致无法保留完整的IP元素。
精简数据集示例
df.head(10).to_dict('list') {'source_ip': ['135.b1d10.d1c38.20', '135.0777d.04511.237', '135.0777d.04511.237', '135.b1d10.d1c38.119', '135.b1d10.13fe9.56', '135.b1d10.d1c38.72', '135.b1d10.d1c38.126', '135.0777d.04511.237', '135.0777d.04511.237', '135.0777d.04511.237'], 'destination_ip': ['135.0777d.04511.237', '135.b1d10.13fe9.91', '135.b1d10.13fe9.71', '135.0777d.04511.237', '135.0777d.04511.237', '135.0777d.04511.237', '135.0777d.04511.237', '135.b1d10.d1c38.37', '135.b1d10.d1c38.112', '135.b1d10.d1c38.20'], 'start_time': [1415749946, 1415477729, 1415702327, 1415754478, 1415749597, 1415745508, 1415754317, 1415427333, 1415584036, 1415582789]}
原代码问题分析
原代码的核心问题是:首次添加目标IP时用字符串存储,后续追加时将现有值与新IP打包成列表,导致嵌套结构;展平时使用extend方法,若现有值是字符串,extend会将其拆分为单个字符,破坏IP的完整性。
修正后的代码
核心思路是从一开始就将track_ip的初始值设为列表,后续直接用append追加元素,彻底避免嵌套列表的产生:
import numpy as np import pandas as pd df = pd.read_csv('df.csv') # 初始化衍生列 df['time_since_last'] = 0 df['diff_destination_ip'] = 0 last_time = dict() track_ip = dict() for i, row in df.iterrows(): src_ip = row['source_ip'] dst_ip = row['destination_ip'] if src_ip in last_time: # 计算当前事件与上次事件的时间间隔 df.loc[i, 'time_since_last'] = row['start_time'] - last_time[src_ip] # 判断当前目标IP是否未出现在历史记录中 if dst_ip not in track_ip[src_ip]: df.loc[i, 'diff_destination_ip'] = 1 # 更新当前源IP的最后事件时间 last_time[src_ip] = row['start_time'] # 维护目标IP列表:初始就用列表存储,避免嵌套 if src_ip in track_ip: track_ip[src_ip].append(dst_ip) else: track_ip[src_ip] = [dst_ip]
效果验证
运行修正后的代码后,track_ip会生成完全扁平的结构,不会拆分IP字符:
print(track_ip) # 输出: {'135.b1d10.d1c38.20': ['135.0777d.04511.237'], '135.0777d.04511.237': ['135.b1d10.13fe9.91', '135.b1d10.13fe9.71', '135.b1d10.d1c38.37', '135.b1d10.d1c38.112', '135.b1d10.d1c38.20'], '135.b1d10.d1c38.119': ['135.0777d.04511.237'], '135.b1d10.13fe9.56': ['135.0777d.04511.237'], '135.b1d10.d1c38.72': ['135.0777d.04511.237'], '135.b1d10.d1c38.126': ['135.0777d.04511.237']}
可选:匹配期望的混合结构(单个IP用字符串)
如果需要和预期输出完全一致(单个目标IP时用字符串,多个时用列表),可在循环结束后添加一段后处理代码:
# 将仅含一个元素的列表转为字符串 for src in track_ip: if len(track_ip[src]) == 1: track_ip[src] = track_ip[src][0]
处理后即可得到完全符合期望的输出结果。
内容的提问来源于stack exchange,提问作者Mehran
相关产品推荐
相关产品推荐

