You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA如何编写Do循环选取Excel数据直至求和等于指定目标值

你这个需求本质是子集和问题,28万行的数据量下,别写那种逐行枚举的暴力Do循环,算到宇宙毁灭都出不了结果,必须先做数据剪枝,再用栈结构配合Do循环实现带回溯的查找逻辑,才能在可接受的时间内跑出结果。

前置准备(不做这步代码跑不动)
  • 先筛除所有金额大于1500000的行:这类小票只要选了总额直接超标,完全没有参与计算的必要,先批量删掉减少数据量。
  • 把剩余数据按金额降序排序:从大额小票开始凑,能最快触发“加了就超”的剪枝条件,比乱序/升序的计算效率高上万倍。
  • 把清洗完的金额数据一次性读入VBA数组,全程在内存里运算,不要每次循环都读单元格——单元格对象的读写速度比内存数组慢上百倍,28万行数据直接操作单元格会卡到死机。
核心Do循环逻辑(用栈模拟回溯,避免VBA递归深度溢出问题)

先初始化固定变量:

Const TARGET As Double = 1500000
Dim dataArr() As Double ' 存清洗排序后的所有小票金额
Dim currentSum As Double ' 当前选中小票的总金额,初始为0
Dim stack() As Long ' 存当前选中的小票在数组里的索引,模拟选择路径
Dim ptr As Long ' 当前遍历到的数组下标,初始为0
Dim timeOut As Date ' 超时时间,避免无意义等待
currentSum = 0
ptr = 0
ReDim stack(-1 To -1) ' 初始化空栈
timeOut = Now() + TimeSerial(0, 10, 0) ' 设10分钟超时,可自行调整

外层套Do循环,触发终止条件就退出:

Do
    ' 终止条件1:找到精确解(浮点运算留0.01美元容差),直接退出
    If Abs(currentSum - TARGET) < 0.01 Then
        Exit Do
    End If
    ' 终止条件2:超时,退出返回当前最接近的近似解
    If Now() > timeOut Then
        Exit Do
    End If
    ' 终止条件3:所有组合遍历完没找到解,退出
    If ptr > UBound(dataArr) And UBound(stack) < 0 Then
        Exit Do
    End If

    If currentSum < TARGET And ptr <= UBound(dataArr) Then
        ' 尝试加当前指针指向的小票,不超目标就选中
        If currentSum + dataArr(ptr) <= TARGET + 0.01 Then
            ' 把当前索引压栈,累加金额,指针下移
            ReDim Preserve stack(UBound(stack) + 1)
            stack(UBound(stack)) = ptr
            currentSum = currentSum + dataArr(ptr)
            ptr = ptr + 1
        Else
            ' 加了就超,直接跳过这个小票,指针下移
            ptr = ptr + 1
        End If
    Else
        ' 指针走到头还没凑够,回溯退一步
        Dim lastIdx As Long
        lastIdx = stack(UBound(stack))
        ' 把最后选的小票弹出栈,减去对应金额
        currentSum = currentSum - dataArr(lastIdx)
        If UBound(stack) = 0 Then
            ReDim stack(-1 To -1)
        Else
            ReDim Preserve stack(UBound(stack) - 1)
        End If
        ' 指针移到被弹出小票的下一位,重新尝试
        ptr = lastIdx + 1
    End If
Loop

循环结束后,stack数组里存的索引对应的小票,就是符合要求(或者超时情况下最接近要求)的结果,直接读出来写到工作表里即可。

注意事项

28万条随机数值的精确子集和本身存在的概率极低,不要死等精确结果。如果业务允许小额误差,可以在凑到剩余差额小于你设定的误差阈值(比如1美元)时,直接从剩余小票里找和差额最接近的小票补上,几秒就能出可用结果,没必要跑几小时找精确解。
别尝试纯暴力逐行枚举的Do循环写法:28万条数据的可选组合数是2的28万次方,这个量级的计算量哪怕用超级计算机都跑不完,没有剪枝的逻辑写了也是白写。

内容的提问来源于stack exchange,提问作者lbochitt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 23:10:01