在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;
}
)
)
);