对数据行进行分组,并在每组中对一列求和并连接另一列



在php中,我有一个关联行的索引数组,如下所示:

$the_array = [
['id' => 1, 'value' => 10, 'name' => 'apple'],
['id' => 1, 'value' => 20, 'name' => 'orange'],
['id' => 1, 'value' => 30, 'name' => 'banana'],
['id' => 2, 'value' => 100, 'name' => 'car'], 
['id' => 2, 'value' => 200, 'name' => 'bicycle'],
];

,我想通过对id值分组来重组它,在每个组中,我想对value值求和,并使name值的逗号分隔字符串。

[
['id' => 1, 'value' => 60,  'name' => 'apple,orange,banana'],
['id' => 2, 'value' => 300, 'name' => 'car,bicycle']
]

这是我尝试过的:

function group_by($key, $data) {
$result = array();
foreach($data as $val) {
if(array_key_exists($key, $val)){
$result[$val[$key]][] = $val;
}else{
$result[""][] = $val;
}
}
return $result;
}

它不工作,结果是错误的/不完整的。

我将创建一个中间数组,该数组首先通过id分组为数组键,然后使用它来调用array_column()array_sum()implode()的组合,以生成您的总和value和组合name字符串。

$temp_array = [];
foreach ($the_array as $init) {
// Initially, group them on the id key as sub-arrays
$temp_array[$init['id']][] = $init;
}
$result = [];
foreach ($temp_array as $id => $arr) {
// Loop once for each id ($temp_array has 2 elements from your sample)
// And add an element to $result
$result[] = [
'id' => $id,
// Sum the value subkeys
// array_column() returns just the key 'value' as an array
// array_sum() adds them
'value' => array_sum(array_column($arr, 'value')),
// implode the name subkeys into a string
'name' => implode(',', array_column($arr, 'name'))
];
}
print_r($result);
Array
(
[0] => Array
(
[id] => 1
[value] => 60
[name] => apple,orange,banana
)
[1] => Array
(
[id] => 2
[value] => 300
[name] => car,bicycle
)
)

虽然这个问题已经有了答案,但这里有一种替代方法可以在一个循环中完成所有这些。

如果您跟踪一个小映射,将原始id映射到它们各自的数组索引。

$result = [];
$map = [];
foreach ($the_array as $subarray) {
$id = $subarray['id'];
// First time we encounter the id thus we can safely push it into result
if (!key_exists($id, $map)) {
// array_push returns the number of elements
// since we push one at a time we can directly get the index.
$index = array_push($result, $subarray) - 1;
$map[$id] = $index;
continue;
}
// If the id is already present in our map we can simply
// update the running sum for the values and concat the
// product names.
$index = $map[$id];
$result[$index]['value'] += $subarray['value'];
$result[$index]['name'] .= ",{$subarray['name']}";
}
echo '<pre>';
print_r($result);
echo '</pre>';

结果:

Array
(
[0] => Array
(
[id] => 1
[value] => 60
[name] => apple,orange,banana
)
[1] => Array
(
[id] => 2
[value] => 300
[name] => car,bicycle
)
)

不需要编写多个循环或保存索引映射。最简单、最直接的方法是根据。

分组的值使用临时的第一级键。下面的两个代码片段生成相同的输出,并具有相同的内部处理。这两个代码段之间的唯一区别是,一个使用语言构造迭代输入数据,另一个使用函数迭代。

在遍历数据时,根据每一行的id值向结果数组应用临时键。如果第一次遇到给定的id,则将整行数据存储到组中。如果不是第一次遇到给定的id,则将value的值添加到先前的value的值,并将新的name的值连接到先前存储在组中的name的值。

完成后,您可能希望通过调用array_values()来重新索引第一层。

经典foreach():(Demo)

$result = [];
foreach ($the_array as $row) {
if (!isset($result[$row['id']])) {
$result[$row['id']] = $row;
} else {
$result[$row['id']]['value'] += $row['value'];
$result[$row['id']]['name'] .= ",{$row['name']}";
}
}
var_export(array_values($result));

function style witharray_reduce(): (Demo)

var_export(
array_values(
array_reduce(
$the_array,
function ($carry, $row) {
if (!isset($carry[$row['id']])) {
$carry[$row['id']] = $row;
} else {
$carry[$row['id']]['value'] += $row['value'];
$carry[$row['id']]['name'] .= ",{$row['name']}";
}
return $carry;
}
)
)
);

最新更新