对数据行进行分组,并在每组中对一列求和并连接另一列
Group rows of data and in each group sum one column and concatenate another column
在 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;
}
它不起作用,结果是 wrong/incomplete。
我会创建一个中间数组,它首先按 id
分组到数组键中,然后使用它来调用 array_column()
with 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));
array_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;
}
)
)
);
在 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;
}
它不起作用,结果是 wrong/incomplete。
我会创建一个中间数组,它首先按 id
分组到数组键中,然后使用它来调用 array_column()
with 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));
array_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;
}
)
)
);