如何基于含Start、End、Value列的CSV高效创建Python字典?
高效实现区间映射的Python方案
不用把区间内每个整数展开存储,推荐根据使用场景选择以下两种方案:
方案1:区间存储 + 二分查找查询(最优性能,推荐绝大多数场景)
核心逻辑是仅存储CSV里的原始区间条目,查询时通过二分查找快速匹配所属区间,内存占用和查询效率都远高于展开全量整数的方案。
实现代码
import csv import bisect # 读取CSV并构建排序后的区间索引 sorted_starts = [] sorted_ends = [] sorted_values = [] with open("你的文件路径.csv", "r", encoding="utf-8") as f: reader = csv.DictReader(f) raw_intervals = [] for row in reader: start = int(row["Start"]) end = int(row["End"]) value = int(row["Value"]) raw_intervals.append((start, end, value)) # 按区间起始值排序,方便后续二分查找 raw_intervals.sort(key=lambda x: x[0]) for start, end, value in raw_intervals: sorted_starts.append(start) sorted_ends.append(end + 1) # 转左闭右开区间,简化边界判断 sorted_values.append(value) # 查询函数 def query_value(num: int) -> int | None: # 找到最后一个起始值小于等于num的区间 idx = bisect.bisect_right(sorted_starts, num) - 1 # 校验num是否在该区间的结束值范围内 if idx >= 0 and num < sorted_ends[idx]: return sorted_values[idx] # 无匹配区间返回None,可按需修改为默认值 return None
方案优势
- 内存占用极低:仅存储和CSV行数相同的条目,哪怕区间跨度是几十万几百万也不会增加内存消耗
- 查询效率高:单次查询时间复杂度为O(log n),n为CSV行数,远高于遍历全量字典的效率
方案2:自定义字典类(兼容原生字典使用习惯)
如果你需要使用dict[整数]的方式直接取值,不需要额外调用查询函数,可以继承原生字典重写缺失键匹配逻辑,无需提前存储所有整数键:
class IntervalDict(dict): def __init__(self, sorted_starts: list[int], sorted_ends: list[int], sorted_values: list[int]): self.sorted_starts = sorted_starts self.sorted_ends = sorted_ends self.sorted_values = sorted_values # 可选:开启查询缓存,查询过的键会存入原生字典,下次查询直接返回 self.enable_cache = True def __missing__(self, key: int): if not isinstance(key, int): raise KeyError(key) idx = bisect.bisect_right(self.sorted_starts, key) - 1 if idx >= 0 and key < self.sorted_ends[idx]: val = self.sorted_values[idx] if self.enable_cache: self[key] = val return val raise KeyError(key) # 用法示例 my_dict = IntervalDict(sorted_starts, sorted_ends, sorted_values) print(my_dict[20]) # 输出30 print(my_dict[15000]) # 输出1
小数据量简化方案
如果你的CSV行数小于100行,不需要二分查找,直接遍历匹配区间即可,代码更简洁:
import csv interval_map = [] with open("你的文件路径.csv", "r", encoding="utf-8") as f: reader = csv.DictReader(f) for row in reader: interval_map.append((int(row["Start"]), int(row["End"]), int(row["Value"]))) def query_value_small(num: int) -> int | None: for start, end, val in interval_map: if start <= num <= end: return val return None
内容的提问来源于stack exchange,提问作者lunbox
相关产品推荐
相关产品推荐

