【问题标题】:Merge arrays on one column, sum other column values in each group合并一列上的数组,对每组中的其他列值求和
【发布时间】:2018-02-15 15:05:39
【问题描述】:

我有 2 个数组:

$array1 = [
    ['amount' => 21600.00, 'rows' => 2, 'student_id' => 1],
];

$array2 = [
    ['amount' => 541990.00, 'rows' => 512, 'student_id' => 1],
    ['amount' => 347480.00, 'rows' => 281, 'student_id' => 2],
    ['amount' => 507400.00, 'rows' => 214, 'student_id' => 3],
];

我想基于相同的student_id 值合并两个数组。当在两个数组中都找到 student_id 时,我想将两个 amount 值和两个 rows 值相加。

预期结果:

array (
  0 => 
  array (
    'amount' => 563590.0,
    'rows' => 514,
    'student_id' => 1,
  ),
  1 => 
  array (
    'amount' => 347480.0,
    'rows' => 281,
    'student_id' => 2,
  ),
  2 => 
  array (
    'amount' => 507400.0,
    'rows' => 214,
    'student_id' => 3,
  ),
)

我尝试过使用array_merge()array_merge_recursive(),但它们没有给我预期的结果。

【问题讨论】:

  • 我只会使用 foreach() 循环
  • 为什么你有这两个具有相同相似结构的数组?你是从两个不同的表中选择它吗?我认为您应该在数据库级别执行此操作。
  • 是的,我知道,但我无法通过查询来完成。所以我应该通过 PHP 来做。顺便说一句,我现在从拉胡尔那里得到了答案

标签: php arrays multidimensional-array merge grouping


【解决方案1】:

这是解决您问题的简单代码,

count($arr) > count($arr0) ? ($greater = $arr AND $smaller = $arr0) : ($smaller = $arr AND $greater = $arr0);
foreach ($greater as $key => &$value) {
    foreach ($smaller as $key1 => &$value1) {
        if($value['student_id'] == $value1['student_id']){
            $value['amount'] +=$value1['amount'];
            $value['rows'] +=$value1['rows'];
        }
    }
}

检查输出here

【讨论】:

    【解决方案2】:

    关于组合查询的注释可能是更好的方法。

    SELECT student_id, sum(amount) as amount, sum(rows) as rows 
    from students
    group by student_id;
    

    但是,如果您不能通过查询来完成,PHP 本身不会将数组值添加到一起(这没有意义)

    这就是你必须做的事情

    function arrayMergeMatch(&$a, &$b)
    {
        foreach ($a as $key => $value) {
            if (array_key_exists($key, $b)) {
                // there's a matching index in both a & b
                $a[$key] = [
                    $a[$key]['amount'] += $b[$key]['amount'],
                    $a[$key]['rows'] += $b[$key]['rows'],
                    $a[$key]['student_id'],
                ];
            }
        }
    }
    
    $firstArray = $secondArray = [];
    
    $firstArray[0] = [
        'amount' => 21600.00,
        'rows'   => 2,
        'student_id' => 1 
    ];
    
    
    $secondArray[0] = [
        'amount' => 541990.00,
        'rows' => 512,
        'student_id' => 1,
    ];
    
    $secondArray[1] = [
        'amount' => 347480.00,
        'rows' => 281,
        'student_id' => 2,
    ];
    
    $secondArray[2] = [
        'amount' => 507400.00,
        'rows' => 214,
        'student_id' => 3,
    ];
    
    $firstArrayLength  = count($x);
    $secondArrayLength = count($y);
    
    $combinedArray = null;
    
    if ($firstArrayLength > $secondArrayLength) {
        // loop through x checking to see if there's a matching y
        arrayMergeMatch($firstArray, $secondArray);
        $combinedArray = $firstArray;
    }
    else {
        // y is longer than or equal to x, so loop through y, looking for matching
        // index in x
        arrayMergeMatch($secondArray, $firstArray);
        $combinedArray = $secondArray;
    }
    
    print_r($combinedArray);
    

    【讨论】:

      【解决方案3】:

      不需要嵌套循环。会有几种不同的样式,但任务的关键是创建一个结果数组,在迭代传入数据时临时用作查找数组。

      为此,请使用 student_id 值分配临时键。当在结果数组中找到student_id 后,只需将这些值添加到组中存储的相关值中即可。完成迭代后,使用 array_values() 重新索引结果。

      功能风格:(Demo1) (Demo2 - likely slower)

      var_export(
          array_values(
              array_reduce(
                  $array2,
                  function($result, $row) {
                      if (!isset($result[$row['student_id']])) {
                          $result[$row['student_id']] = $row;
                      } else {
                          $result[$row['student_id']]['amount'] += $row['amount'];
                          $result[$row['student_id']]['rows'] += $row['rows'];
                      }
                      return $result;
                  },
                  array_column($array1, null, 'student_id')
              )
          )
      );
      

      语言构造循环:(Demo1) (Demo2 - likely slower)

      $result = array_column($array1, null, 'student_id');
      foreach ($array2 as $row) {
          if (!isset($result[$row['student_id']])) {
              $result[$row['student_id']] = $row;
          } else {
              $result[$row['student_id']]['amount'] += $row['amount'];
              $result[$row['student_id']]['rows'] += $row['rows'];
          }
      }
      var_export(array_values($result));
      

      以上所有 sn-ps 都应该使用而不是其他发布的答案,因为它们的迭代次数永远不会超过m + n。以下是对其他答案的批评:

      • Rahul 的答案是使用嵌套循环——这意味着迭代次数将为m*n(array1 中的行数乘以 array2 中的行数)——这是非常间接/低效的。即使使用了break,它仍然不会像我的 sn-ps 那样直接/高效。

      • Kearney 的回答完全忽略了对 student_id 值进行排序的要求(即使在修复了 $x$y 错别字之后)。这个基于 php 的答案是完全不正确Proof. 不太重要的是,$b 不需要通过引用进行修改。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-04
        • 2012-01-03
        • 1970-01-01
        • 1970-01-01
        • 2020-12-29
        • 1970-01-01
        相关资源
        最近更新 更多