VB.NET实现仅保留泛型Double列表[360 ; 720]区间值的高效方法
现有实现的核心问题
你当前的代码存在三个明显的效率和可靠性问题:
- 强依赖列表元素升序排列的前提,没有边界保护:如果列表中所有元素都小于360,循环删除到列表为空时,
Loop Until list(index) > 360的判断会直接触发索引越界异常 - 零散调用
RemoveAt的开销极高:List(Of T)的RemoveAt方法每次执行都需要把删除位置后方的所有元素整体向前挪动一位,多次删除的时间复杂度会达到O(n²),长列表场景下性能会急剧下降 - 逻辑割裂:拆分两段代码分别处理小于360、大于720的元素,没有统一的过滤判断,维护成本高
更优的实现方案
根据你对列表是否有序的确认,分两种最常用的优化场景:
通用稳妥方案(无序列表也可用,推荐优先使用)
直接调用List自带的RemoveAll方法,这是.NET框架针对批量删除场景原生优化的方法,整体仅需单次遍历列表,一次性把符合删除条件的元素批量挪移,时间复杂度仅O(n),没有零散删除的额外开销:
' 统一删除所有不在[360,720]闭区间内的元素 list.RemoveAll(Function(x) x < 360 OrElse x > 720)
如果你的业务逻辑允许重新生成列表,用LINQ过滤的写法可读性更强,性能和RemoveAll基本持平:
list = New List(Of Double)(list.Where(Function(x) x >= 360 AndAlso x <= 720))
有序列表极致优化方案(确认列表严格升序时使用)
如果你能100%确认列表元素是升序排列的(也就是你之前代码隐含的前提),完全不需要全列表扫描,直接用二分查找定位两个边界的索引,通过RemoveRange一次性删除整段无效元素,时间复杂度可以降低到O(log n),长列表场景下性能比全量扫描再提一个量级:
' 定位左边界:找到第一个>=360的元素位置 Dim leftBound = list.BinarySearch(360) If leftBound < 0 Then leftBound = Not leftBound ' 兼容二分查找未命中时的返回值规则 If leftBound > 0 Then list.RemoveRange(0, leftBound) ' 一次删除左边界前的所有无效元素 ' 定位右边界:找到第一个>720的元素位置 Dim rightBound = list.BinarySearch(720 + Double.Epsilon) If rightBound < 0 Then rightBound = Not rightBound If rightBound < list.Count Then list.RemoveRange(rightBound, list.Count - rightBound) ' 一次删除右边界后的所有无效元素
对比你原来的逐次删除逻辑:比如前1000个元素都小于360,逐次删除的总元素挪移次数接近100万次,而用RemoveRange一次性删除的总挪移次数仅为剩余有效元素的总长度,效率差距可以达到两个数量级。
内容的提问来源于stack exchange,提问作者Tobuscous
相关产品推荐
相关产品推荐

