0

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

它不起作用,结果错误/不完整。

4

3 回答 3

1

我将创建一个中间数组,该数组首先分组为数组键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
        )

)
于 2021-01-25T16:03:17.270 回答
1

尽管已经回答了这个问题,但这里有另一种方法可以在一个循环中完成所有这些操作。

如果您跟踪将原始 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
        )
)
于 2021-01-25T17:03:22.700 回答
0

不必编写多个循环或保留索引映射。最精简、直接的方法是根据分组的值使用临时的一级键。

下面的两个片段都生成相同的输出并具有相同的内部处理。两个片段之间的唯一区别是一个使用语言结构迭代输入数据,另一个使用函数迭代。

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

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

经典foreach():(演示

$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():(演示

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;
            }
        )
    )
);
于 2021-04-25T16:24:21.377 回答