根据一列值对子数组数据进行分组合并

Group and merge subarray data based on one column value

我在下面的 PHP 代码中有一个数组,我想将这个数组转换为按数据值分组。简化数组总是很困难。

原数组:

  Array
  (
    [0] => Array
        (
            [date] => 2017-08-22
            [AAA] => 1231
        )
    [1] => Array
        (
            [date] => 2017-08-21
            [AAA] => 1172
        )
    [2] => Array
        (
            [date] => 2017-08-20
            [AAA] => 1125
        )
    [3] => Array
        (
            [date] => 2017-08-21
            [BBB] => 251
        )
    [4] => Array
        (
            [date] => 2017-08-20
            [BBB] => 21773
        )
    [5] => Array
        (
            [date] => 2017-08-22
            [CCC] => 3750
        ) 
    [6] => Array
        (
            [date] => 2017-08-20
            [CCC] => 321750
        )
  )

下面是我想要的数组:

  Array
  (
    [2017-08-22] => Array
        (
            [AAA] => 1231 
            [CCC] => 3750
        )
    [2017-08-21] => Array
        (
            [AAA] => 1172
            [BBB] => 251
        )
    [2017-08-20] => Array
        (
            [AAA] => 1125
            [BBB] => 21773
            [CCC] => 321750
        )
  )

如果数据不存在,空的null值也是可以的。 [BBB] => 2017-08-22 为空。 有人可以帮忙吗?提前致谢...

一个简单的循环就可以做到这一点..

$group = [];
foreach ($data as $item)  {
    if (!isset($group[$item['date']])) {
        $group[$item['date']] = [];
    }
    foreach ($item as $key => $value) {
        if ($key == 'date') continue;
        $group[$item['date']][$key] = $value;
    }
}

此处:这应该可以完成工作。

$dst_array = array();
foreach ($array as $outerval) {
    foreach ($outerval as $key => $innerval) {
        if ($key != 'date') {
            $dst_array[$outerval['date']][$key] = $innerval;
        }
    }
}

它遍历数组,然后遍历每个子数组中的条目。任何不是日期的 any 都会分配到与其日期对应的子数组中的目标数组中,并使用其自己的当前键。

我相信这个解决方案对你有用:

<?php
$array = Array
(
    0 => Array
    (
        'date' => '2017-08-22',
        'AAA' => '1231',
    ),
    1 => Array
    (
        'date' => '2017-08-21',
        'AAA' => '1172',
    ),
    2 => Array
    (
        'date' => '2017-08-20',
        'AAA' => '1125'
    ),
    3 => Array
    (
        'date' => '2017-08-21',
        'BBB' => '251'
    ),
    4 => Array
    (
        'date' => '2017-08-20',
        'BBB' => '21773',
    ),
    5 => Array
    (
        'date' => '2017-08-22',
        'CCC' => '3750'
    ),
    6 => Array
    (
        'date' => '2017-08-20',
        'CCC' => '321750'
    )
);
echo '<pre>';
$array1 = array('AAA' => null, 'BBB' => null, 'CCC' => null);
$array2 = array();

array_walk($array, function ($v) use (&$array2, $array1) {
    $a = $v['date'];
    if (!isset($array2[$a])) {
        $array2[$a] = $array1;
    }
    unset($v['date']);
    $array2[$a] = array_merge($array2[$a], $v);
});

print_r($array2);

输出

Array
(
    [2017-08-22] => Array
        (
            [AAA] => 1231
            [BBB] => 
            [CCC] => 3750
        )

    [2017-08-21] => Array
        (
            [AAA] => 1172
            [BBB] => 251
            [CCC] => 
        )

    [2017-08-20] => Array
        (
            [AAA] => 1125
            [BBB] => 21773
            [CCC] => 321750
        )

)

检查输出:https://3v4l.org/NvLB8

另一种使用数组内部指针的方法(快速且肮脏):

$newArray = [];
foreach ($array as $childArray) {
    $date = current($childArray);

    $value = next($childArray);  // this advances the internal pointer..
    $key = key($childArray);     // ..so that you get the correct key here

    $newArray[$date][$key] = $value;
}

这当然只适用于给定的数组结构。

PHP函数的另一个完美用法示例array_reduce():

// The input array
$input = array(
    0 => array(
        'date' => '2017-08-22',
        'AAA'  => '1231',
    ),
    // The rest of your array here...
);


$output = array_reduce(
    $input,
    function (array $carry, array $item) {
        // Extract the date into a local variable for readability and speed
        // It is used several times below
        $date = $item['date'];
        // Initialize the group for this date if it doesn't exist
        if (! array_key_exists($date, $carry)) {
            $carry[$date] = array();
        }

        // Remove the date from the item...
        // ...and merge the rest into the group of this date
        unset($item['date']);
        $carry[$date] = array_merge($carry[$date], $item);

        // Return the partial result
        return $carry;
    },
    array()
);

问题不清楚。如果一个键 (AAA f.e) 在两个或多个日期出现,预期结果是什么?此答案仅保留与其关联的最后一个值。

我绝对不会推荐任何涉及多个循环的技术——这个过程当然可以在一个循环中执行。

如果您喜欢语言构造迭代,请使用 foreach() 循环:(Demo)

$result = [];
foreach ($array as $row) {
    $date = $row['date'];
    unset($row['date']);
    $result[$date] = array_merge($result[$date] ?? [], $row);
}
var_export($result);

如果你喜欢使用函数式编程和较少的全局变量,请使用array_reduce():(Demo)

var_export(
    array_reduce(
        $array, 
        function($accumulator, $row) {
            $date = $row['date'];
            unset($row['date']);
            $accumulator[$date] = array_merge($accumulator[$date] ?? [], $row);
            return $accumulator;
        },
        []
    )
);

这些技术无条件地将数据推入具有基于日期列值的键的子数组。

即使您的子数组元素的顺序发生变化,上述技术也会始终如一地起作用。

??(空合并运算符)是为了确保 array_merge() 始终在第一个参数中有一个数组——如果处理给定日期的第一次出现,您只需合并当前带有空数组的迭代数据(unset() 删除日期元素后剩下的数据)。