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

问题描述 投票:0回答:6

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

原始数组:

$array = [
    ['date' => '2017-08-22', 'AAA' => 1231],
    ['date' => '2017-08-21', 'AAA' => 1172],
    ['date' => '2017-08-20', 'AAA' => 1125],
    ['date' => '2017-08-21', 'BBB' => 251],
    ['date' => '2017-08-20', 'BBB' => 21773],
    ['date' => '2017-08-22', 'CCC' => 3750],
    ['date' => '2017-08-20', 'CCC' => 321750],
];

下面是我想要的数组:

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

如果数据不存在,空值也可以。 [BBB] => 2017-08-22 为 NULL。 有人可以帮忙吗?预先感谢...

php arrays multidimensional-array grouping array-merge
6个回答
2
投票

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

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

1
投票

这里:这应该可以完成工作。

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

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


1
投票

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

如果您喜欢语言构造迭代,请使用

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()
删除日期元素)并使用空数组。


0
投票

我相信这个解决方案适合您:

<?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


0
投票

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

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

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


0
投票

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) 出现在两个或多个日期上,预期结果是什么?此答案仅保留与其关联的最后一个值。

© www.soinside.com 2019 - 2024. All rights reserved.