【问题标题】:How to merge subarrays using keys and sum the values?如何使用键合并子数组并对值求和?
【发布时间】:2018-06-29 14:12:48
【问题描述】:

我对 PHP 还很陌生,在处理数组和合并数据时遇到了一些问题。我有以下从 foreach 循环创建的数组:

array(1) {
    [36868]=> int(3)
}
array(1) {
    [2112]=> int(3)
} 
array(1) { 
    [35901]=> int(3) 
} 
array(1) { 
    [6496]=> int(3) 
} 
array(1) { 
    [87]=> int(3) 
} 
array(1) { 
    [36868]=> int(3) 
} 
array(1) { 
    [68]=> int(3) 
} 
array(1) { 
    [9068]=> int(3) 
} 
array(1) { 
    [47]=> int(3) 
}

每个数组中的键是一个用户 ID,所以我需要保留它,但我只想要每个键的一个实例,并且在有重复键的地方,对值求和。像这样:

array(1) {
    [36868]=> int(6)
}
array(1) {
    [2112]=> int(3)
} 
array(1) { 
    [35901]=> int(3) 
} 
array(1) { 
    [6496]=> int(3) 
} 
array(1) { 
    [87]=> int(3) 
} 
array(1) { 
    [68]=> int(3) 
} 
array(1) { 
    [9068]=> int(3) 
} 
array(1) { 
    [47]=> int(3) 
}

我试过循环遍历数组:

foreach ($array as $key => &$value) {
    if ($value[0] == $value[1]) {
        $value[1] += $value[1];
    }
}

但没有运气。我也尝试过以不同的方式渲染数组,即[userid]=>1,[score]=>3,我觉得我有点绕圈子,所以任何帮助都将不胜感激。

【问题讨论】:

  • 你需要单独的数组吗?还是可以合并?
  • @DavidPassmore 它可以合并,我之前也尝试过,但也没有那么幸运

标签: php multidimensional-array merge sum


【解决方案1】:
$data <-- this is your original array

$result = array_reduce(
    $data,
    function($carry, $item) {
        foreach ($item as $id => $score) {
            if (array_key_exists($id, $carry)) {
                $carry[$id] += $score;
            } else {
                $carry[$id] = $score;
            }
        }

        return $carry;
    },
    []
);

如果您确定每个项目仅包含 1 个条目,您还可以简化回调以不使用 foreach:

$result = array_reduce(
    $data,
    function ($carry, $item) {
        $score = reset($item); 
        $id = key($item);

        if (array_key_exists($id, $carry)) {
            $carry[$id] += $score;
        } else {
            $carry[$id] = $score;
        }

        return $carry;
    },
    []
);

您也可以继续使用 foreach:

/** foreach to create a $data array like described below and afterwards do this: **/
$result = [];
foreach($data as $row) {
    $score = reset($row);
    $id = key($row);

    if (array_key_exists($id, $result)) {
        $result[$id] += $score;
    } else {
        $result[$id] = $score;
    }
}

这将采用一个数组$data,如下所示:

array(
    array('1' => 3),
    array('1' => 3),
    array('2' => 3),
);

并像这样创建变量$result

array(
    '1' => 6,
    '2' => 3,
);

【讨论】:

  • 感谢 dbrumann,我已经尝试过了,但我得到的只是 9 x NULL ` foreach($results as $key => $value) { $data = array($value[ 'id'] => 3); array_reduce( $data, function($carry, $item) { foreach ($item as $id => $score) { $carry[$id] += $score; } return $carry; }, [] ); var_dump($carry); }`
  • 对不起,我没有意识到你不能在 cmets 中格式化:/
  • 我更新了示例。您必须从函数中获取最终结果,而不是重用 $carry。你也不需要foreach。只需将原始数组作为第一个参数传递给array_reduce()(将$data 替换为$results
  • 我认为它不会将我的 $data 数组传递给 array_reduce,因为我无法在任何时候通过每一行代码转储任何内容以查看它在做什么,它始终为 NULL 或空的。我是否应该无法在其中一个点上看到至少一些数据?
  • 我已经改变了我的 $data = array($value['id'] => 3);到 $data[] = $value['id'];这解决了我的问题。感谢您的耐心 dbrumann 并花时间帮我解决这个问题!
【解决方案2】:

这是一个不会产生通知的干净方法。合并求和数组数据时,有效的方法是生成临时键并使用非常快的isset() 函数。我本可以使用current()key() 来访问单独的子数组元素,但是第二个foreach 控制结构实际上更快更紧凑。 (参考: https://stackoverflow.com/a/21219594/2943403)

代码:(Demo)

$array = [
    [36868 => 3],
    [2112 => 3],
    [35901 => 3],
    [6496 => 3],
    [87 => 3],
    [36868 => 3],
    [68 => 3],
    [9068 => 3],
    [47 => 3]
];

$result = [];
foreach ($array as $subarray) {
    foreach ($subarray as $k => $v) {
        if (!isset($result[$k])) {
            $result[$k] = $subarray;
        } else {
            $result[$k][$k] += $v;
        }
    }
}
var_export(array_values($result));

输出:

array (
  0 => 
  array (
    36868 => 6,
  ),
  1 => 
  array (
    2112 => 3,
  ),
  2 => 
  array (
    35901 => 3,
  ),
  3 => 
  array (
    6496 => 3,
  ),
  4 => 
  array (
    87 => 3,
  ),
  5 => 
  array (
    68 => 3,
  ),
  6 => 
  array (
    9068 => 3,
  ),
  7 => 
  array (
    47 => 3,
  ),
)

【讨论】:

    猜你喜欢
    • 2011-10-29
    • 1970-01-01
    • 1970-01-01
    • 2021-12-27
    • 2013-06-11
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多