PHP中多维数组按键分组并聚合数值的技巧

聖光之護
发布: 2025-10-05 10:06:01
原创
458人浏览过

PHP中多维数组按键分组并聚合数值的技巧

本文详细介绍了在PHP中如何将多个并行数组根据其中一个数组的键进行分组,并对其他关联数组中的数值进行求和。文章提供了三种不同的实现策略,包括原地修改与重新索引、构建新数组并维护索引,以及利用引用高效构建结果集,旨在帮助开发者选择最适合其场景的解决方案。

在数据处理中,我们经常会遇到需要对结构化数据进行聚合的场景。例如,给定一组并行数组,其中一个数组作为分组依据(如状态),而其他数组包含需要聚合(如求和)的数值。本教程将探讨几种在php中实现这一目标的高效方法。

问题描述

假设我们有以下几组并行数组,它们在索引上是一一对应的:

$statuses = ['PROSPECT', 'BACKLOG', 'PROSPECT'];
$of_tranxs = [2, 1, 2];
$revs = [3, 1, 3];
$mgps = [4, 1, 4];
登录后复制

我们的目标是根据 $statuses 数组中的值进行分组,并对 of_tranxs、revs 和 mgps 数组中对应的值进行求和。最终输出应是一个结构化的数组,例如:

array(
  'status' => ['PROSPECT', 'BACKLOG'],
  'of_tranx' => [4, 1],
  'rev' => [6, 1],
  'mgp' => [8, 1]
)
登录后复制

下面将介绍三种不同的实现策略。

方法一:原地修改与重新索引

这种方法通过在原始数组上进行操作来聚合数据。它利用一个辅助数组来记录每个分组键首次出现时的索引,后续遇到重复键时,将对应的值累加到首次出现的索引位置,并删除重复项。最后,对所有数组进行重新索引以获得紧凑的结果。

立即学习PHP免费学习笔记(深入)”;

即构数智人
即构数智人

即构数智人是由即构科技推出的AI虚拟数字人视频创作平台,支持数字人形象定制、短视频创作、数字人直播等。

即构数智人 36
查看详情 即构数智人

实现步骤

  1. 遍历作为分组依据的 $statuses 数组。
  2. 使用一个 $found 数组记录每个状态首次出现的原始索引。
  3. 如果当前状态是首次出现,则将其原始索引存入 $found。
  4. 如果当前状态已存在于 $found 中,则将当前索引对应的 of_tranxs、revs 和 mgps 值累加到 $found 中记录的首次出现索引的位置。
  5. 累加完成后,删除当前索引在所有原始数组中的对应元素。
  6. 循环结束后,使用 array_values() 函数对所有数组进行重新索引,移除空缺的键,得到最终结果。

示例代码

<?php
$statuses = ['PROSPECT', 'BACKLOG', 'PROSPECT'];
$of_tranxs = [2, 1, 2];
$revs = [3, 1, 3];
$mgps = [4, 1, 4];

$found = []; // 用于记录每个状态首次出现的索引

foreach ($statuses as $index => $status) {
    if (!isset($found[$status])) {
        // 如果是首次遇到该状态,记录其索引
        $found[$status] = $index;
        continue;
    }
    // 如果该状态已存在,则将当前值累加到首次出现的位置
    $of_tranxs[$found[$status]] += $of_tranxs[$index];
    $revs[$found[$status]] += $revs[$index];
    $mgps[$found[$status]] += $mgps[$index];

    // 删除当前索引处的重复项
    unset($statuses[$index], $of_tranxs[$index], $revs[$index], $mgps[$index]);
}

// 重新索引所有数组,确保键的连续性
$result = [
    'status' => array_values($statuses),
    'of_tranx' => array_values($of_tranxs),
    'rev' => array_values($revs),
    'mgp' => array_values($mgps)
];

var_export($result);
?>
登录后复制

优点与缺点

  • 优点: 内存效率相对较高,因为它直接修改原始数组。
  • 缺点: 破坏性操作,会修改原始数组。代码可读性略低于构建新数组的方法,且最后需要多次调用 array_values()。

方法二:构建新数组并维护索引

此方法通过构建一个新的结果数组来避免对原始数据的修改。它维护一个映射关系,将每个状态映射到新结果数组中的一个递增索引,从而实现数据的聚合。

实现步骤

  1. 初始化一个空的 $result 数组和一个递增的 $i 变量作为新数组的索引。
  2. 初始化一个 $newIndex 数组,用于存储每个状态在新结果数组中的对应索引。
  3. 遍历 $statuses 数组。
  4. 如果当前状态在 $newIndex 中不存在:
    • 将当前状态添加到 $result['status']。
    • 将当前索引对应的 of_tranxs、revs、mgps 值添加到 $result 对应的子数组中。
    • 将当前状态与 $i 进行映射,并将 $i 递增。
  5. 如果当前状态已存在于 $newIndex 中:
    • 获取其在新数组中的索引 $newIndex[$status]。
    • 将当前索引对应的 of_tranxs、revs、mgps 值累加到 $result 中对应索引的位置。

示例代码

<?php
$statuses = ['PROSPECT', 'BACKLOG', 'PROSPECT'];
$of_tranxs = [2, 1, 2];
$revs = [3, 1, 3];
$mgps = [4, 1, 4];

$result = [];
$newIndex = []; // 映射:状态 -> 新数组中的索引
$i = 0;          // 新数组的递增索引

foreach ($statuses as $oldIndex => $status) {
    if (!isset($newIndex[$status])) {
        // 首次遇到该状态,在新数组中创建新条目
        $newIndex[$status] = $i++;
        $result['status'][] = $status;
        $result['of_tranx'][] = $of_tranxs[$oldIndex];
        $result['rev'][] = $revs[$oldIndex];
        $result['mgp'][] = $mgps[$oldIndex];
    } else {
        // 状态已存在,累加到对应位置
        $targetNewIndex = $newIndex[$status];
        $result['of_tranx'][$targetNewIndex] += $of_tranxs[$oldIndex];
        $result['rev'][$targetNewIndex] += $revs[$oldIndex];
        $result['mgp'][$targetNewIndex] += $mgps[$oldIndex];
    }
}

var_export($result);
?>
登录后复制

优点与缺点

  • 优点: 非破坏性操作,原始数组保持不变。代码逻辑清晰,易于理解和维护。
  • 缺点: 需要额外的内存来存储 $result 和 $newIndex 数组。

方法三:利用引用高效构建结果集

这种方法结合了构建新数组的优点,并利用PHP的引用机制,避免了手动管理索引的复杂性,同时减少了 array_values() 的调用。它通过一个临时引用数组来直接操作最终结果数组中的元素。

实现步骤

  1. 初始化一个空的 $result 数组。
  2. 初始化一个 $ref 数组,用于存储每个状态的引用。
  3. 遍历 $statuses 数组。
  4. 如果当前状态在 $ref 中不存在:
    • 创建一个包含当前状态及对应数值的关联数组。
    • 将此关联数组的引用存储到 $ref[$status] 中。
    • 将这个引用推入 $result 数组。这样,对 $ref[$status] 的任何修改都会直接反映到 $result 中。
  5. 如果当前状态已存在于 $ref 中:
    • 通过 $ref[$status] 引用,直接累加对应数值。

示例代码

<?php
$statuses = ['PROSPECT', 'BACKLOG', 'PROSPECT'];
$of_tranxs = [2, 1, 2];
$revs = [3, 1, 3];
$mgps = [4, 1, 4];

$result = [];
$ref = []; // 映射:状态 -> 结果数组中对应元素的引用

foreach ($statuses as $i => $status) {
    if (!isset($ref[$status])) {
        // 首次遇到该状态,创建新的数据结构并将其引用存入 $ref
        $ref[$status] = [
            'status' => $status,
            'of_tranx' => $of_tranxs[$i],
            'rev' => $revs[$i],
            'mgp' => $mgps[$i],
        ];
        // 将引用推入 $result,后续对 $ref[$status] 的修改会直接影响 $result
        $result[] = &$ref[$status];
    } else {
        // 状态已存在,通过引用直接累加值
        $ref[$status]['of_tranx'] += $of_tranxs[$i];
        $ref[$status]['rev'] += $revs[$i];
        $ref[$status]['mgp'] += $mgps[$i];
    }
}

var_export($result);
?>
登录后复制

优点与缺点

  • 优点: 非破坏性操作,原始数组保持不变。代码简洁,无需显式管理新数组的索引。避免了 array_values() 的多次调用。结果数组的每个元素都是一个包含所有相关字段的关联数组,结构更清晰。
  • 缺点: 使用引用可能会增加初学者的理解难度。

注意事项

  • 性能考量: 对于小型数据集,这三种方法的性能差异不大。但对于大型数据集,方法一(原地修改)可能在内存使用上略有优势,因为它避免了创建大量新数组元素。方法三(使用引用)在代码简洁性和避免重复 array_values() 调用方面表现良好,通常是推荐的选择。
  • 代码可读性与维护性: 方法二和方法三通常被认为具有更好的可读性,因为它们不修改原始数据。方法三的输出格式(每个元素都是一个关联数组)在某些场景下可能更易于后续处理。
  • 数据结构: 本教程中,所有数组都是并行且索引一一对应的。如果数据结构更复杂(例如,多维关联数组),则需要调整遍历和聚合逻辑。
  • PHP版本: 示例代码在PHP 7.4及更高版本中均可正常运行。

总结

本文介绍了三种在PHP中根据一个数组分组并聚合其他并行数组数值的方法:原地修改与重新索引、构建新数组并维护索引,以及利用引用高效构建结果集。每种方法都有其独特的优点和适用场景。在实际开发中,开发者应根据项目需求、性能考量和代码可读性偏好来选择最合适的实现策略。通常情况下,方法三(利用引用)在提供清晰输出结构的同时,兼顾了效率和代码简洁性,是一个非常推荐的解决方案。

以上就是PHP中多维数组按键分组并聚合数值的技巧的详细内容,更多请关注php中文网其它相关文章!

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号