Unity中滑块时间值与ArrayList的O(1)复杂度映射查询需求
优化大规模时间序列的O(1)查询方案
嗨,这个性能问题我太懂了——30万条数据每次滑块动都全量遍历,Unity里肯定会掉帧甚至卡顿!咱们直接从根源解决,把每次O(n)的查询改成O(1)的哈希表查找,步骤很清晰:
核心思路:预处理映射字典
既然你是按取整后的时间来匹配,那我们可以提前把时间和对应的对象索引/ID做一次映射,存进Dictionary(哈希表)里,这样每次查询直接查表就行,不用再遍历整个列表。
第一步:替换ArrayList为泛型列表(可选但推荐)
Unity里的ArrayList会有不必要的拆箱装箱开销,建议换成List<float>(存时间)和List<int>(存对象ID),代码更安全也更快:
// 替换原来的ArrayList public List<float> spikeTimes = new List<float> { 1.2f, 5.9f, 9.6f }; public List<int> spikeObjectIds = new List<int> { /* 对应的对象ID */ };
第二步:预处理映射字典
在Start或Awake里只执行一次预处理,把取整后的时间作为键,对应的对象ID列表作为值:
private Dictionary<int, List<int>> _timeToObjectIds; void Start() { // 初始化字典 _timeToObjectIds = new Dictionary<int, List<int>>(); // 遍历所有时间和ID,构建映射 for (int i = 0; i < spikeTimes.Count; i++) { int roundedTime = Mathf.RoundToInt(spikeTimes[i]); int targetId = spikeObjectIds[i]; // 如果这个时间键不存在,就新建一个列表 if (!_timeToObjectIds.ContainsKey(roundedTime)) { _timeToObjectIds[roundedTime] = new List<int>(); } // 把当前ID加入对应时间的列表 _timeToObjectIds[roundedTime].Add(targetId); } }
第三步:修改滑块查询函数
现在滑块变化时直接查字典,复杂度是O(1),完全不会有遍历30万条的开销:
public void SliderFunction(float currentTime) { // 对当前滑块时间取整,和预处理的规则保持一致 int roundedCurrentTime = Mathf.RoundToInt(currentTime); List<int> targetIds = new List<int>(); // 尝试从字典中获取对应ID列表,避免键不存在时抛出异常 if (_timeToObjectIds.TryGetValue(roundedCurrentTime, out var ids)) { targetIds = ids; } // 直接传入ID执行变色操作 ChangeColor(targetIds); }
额外注意事项
- 如果你的时间匹配规则不是取整,而是比如保留一位小数,那可以把时间乘以10转成int作为键(比如
1.2f变成12),避免浮点数作为字典键的精度问题; - 如果运行时会动态新增时间数据,记得同步更新这个字典,而不是重新全量遍历;
- 原代码里的
Update中计算时间增量的逻辑可以稍微优化下,不用每次计算fps,直接用Time.deltaTime更高效:void Update() { if(isPlaying){ timeSlider.value += Time.deltaTime * 1000 * speed; } }
内容的提问来源于stack exchange,提问作者Vincent Erik Wong
相关产品推荐
相关产品推荐

