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

PHP实现数组递归扣减逻辑求助:金额清零及扣减额转移需求

实现递归扣减金额的PHP逻辑

数据说明

原始数据如下:

#    amount   deduction
[0]   50        10
[1]   160       20
[2]   300       20

需求说明

对数组执行递归扣减操作,直至所有金额变为0;当数组中某一项金额为0时,需将其对应的deduction(扣减额)追加至下一项的扣减额中继续扣减,直至所有金额均为0。

计算示例

[0]          [1]          [2]
50  - 10     160 - 20     300 - 20
40  - 10     140 - 20     280 - 20
30  - 10     120 - 20     260 - 20
20  - 10     100 - 20     240 - 20
10  - 10      80 - 20     220 - 20
 0            60 - 30     200 - 20
              30 - 30     180 - 20
              0           160 - 50
                          110 - 50
                           60 - 50
                           10 - 50
                           0

当前编写的PHP代码

foreach($data as $det)
{
   $_monthly_payment = $det->deduction;
   $_beginning_balance = $det->amount;
   $i = 0;

   do{
     $_new_balance = (($i + 1) == 1) ? $_beginning_balance : $_ending_balance;
     $_toward_principal      = $_monthly_payment;
     $_ending_balance        = $_new_balance - $_toward_principal;

     <tr>
        <td><?php echo number_format($_monthly_payment,2); ?></td>
        <td>$<?php echo number_format($_new_balance,2); ?> </td>
        <td>$<?php echo number_format($_toward_principal,2); ?> </td>
        <td>$<?php echo number_format($_ending_balance,2); ?> </td>
     </tr>
   }
   while( $i <= $_ending_balance );
}

集合数据结构(var_dump输出)

object(Illuminate\Support\Collection)#1334 (1) { 
    ["items":protected]=> array(3) { 
        [0]=> object(stdClass)#1341 (26) { 
            ["id"]=> int(130) ["account_name"]=> string(3) "QWE" ["amount"]=> float(50) ["deduction"]=> float(10) ["updated_at"]=> string(19) "2023-01-09 15:49:59" } 
        [1]=> object(stdClass)#1345 (26) { 
            ["id"]=> int(131) ["account_name"]=> string(3) "ABC" ["amount"]=> float(160) ["deduction"]=> float(20) ["updated_at"]=> string(19) "2023-01-09 15:49:59" } 
        [2]=> object(stdClass)#1326 (26) { 
            ["id"]=> int(132) ["account_name"]=> string(3) "XYZ" ["amount"]=> float(300) ["deduction"]=> float(20) ["updated_at"]=> string(19) "2023-01-09 15:49:59" } 
        } 
    }

解决方案代码

以下是实现需求的PHP代码,基于Illuminate集合处理:

// 复制原集合数据,避免修改原始数据,添加状态标记
$processingItems = $data->map(function($item) {
    return (object)[
        'account_name' => $item->account_name,
        'amount' => $item->amount,
        'deduction' => $item->deduction,
        'isCompleted' => false // 标记当前项是否已清零
    ];
})->toArray();

$stepRecords = []; // 记录每一轮的扣减操作

// 循环处理直到所有项都清零
while (true) {
    $allCompleted = true;
    $currentStep = [];

    foreach ($processingItems as $index => &$item) {
        if ($item->isCompleted) {
            $currentStep[$index] = [
                'original' => 0,
                'deduction' => 0,
                'remaining' => 0
            ];
            continue;
        }

        $allCompleted = false;
        // 计算本次扣减额,最后一步直接扣完剩余金额
        $deductAmount = min($item->deduction, $item->amount);
        $remainingAmount = $item->amount - $deductAmount;

        $currentStep[$index] = [
            'original' => $item->amount,
            'deduction' => $deductAmount,
            'remaining' => $remainingAmount
        ];

        $item->amount = $remainingAmount;

        // 如果当前项已清零,将其扣减额追加到下一项
        if ($remainingAmount === 0) {
            $item->isCompleted = true;
            if (isset($processingItems[$index + 1])) {
                $processingItems[$index + 1]->deduction += $item->deduction;
            }
        }
    }

    // 所有项都完成则退出循环
    if ($allCompleted) {
        break;
    }

    $stepRecords[] = $currentStep;
}

// 输出符合示例格式的表格
echo '<table border="1">';
// 表头:显示账户名称
echo '<tr>';
foreach ($processingItems as $item) {
    echo "<th>{$item->account_name}</th>";
}
echo '</tr>';

// 输出每一步的扣减记录
foreach ($stepRecords as $step) {
    echo '<tr>';
    foreach ($step as $col) {
        if ($col['original'] === 0) {
            echo '<td>0</td>';
        } else {
            echo "<td>{$col['original']} - {$col['deduction']}</td>";
        }
    }
    echo '</tr>';
}

// 最后一行显示全0状态
echo '<tr>';
foreach ($processingItems as $item) {
    echo '<td>0</td>';
}
echo '</tr>';
echo '</table>';

代码说明

  1. 数据复制与标记:复制原集合数据并添加isCompleted标记,防止修改原始数据,同时跟踪项是否已清零。
  2. 循环扣减逻辑:每一轮遍历所有未完成的项,执行扣减操作;最后一步直接扣完剩余金额,避免出现负余额。
  3. 扣减额转移:当某一项清零后,将其原始扣减额追加到下一项的扣减额中,实现需求中的累加逻辑。
  4. 记录与输出:每一步的扣减操作都会被记录,最后按照示例格式输出表格,清晰展示每一轮的变化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 09:25:27