Group and merge subarray data based on one column value

给你一囗甜甜゛ 提交于 2020-06-28 03:35:46

问题


I have an array in PHP code below, and I want to convert this array to be grouped by data value. It's always hard to simplify arrays.

Original 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
        )
  )

Below is my desired array:

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

It is also ok to have empty null value if the data doesn't exist. [BBB] => NULL for 2017-08-22. Can anybody help? Thanks in advance...


回答1:


A simple loop should do this..

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



回答2:


Here : this should do the work.

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

It iterates through the array and then through the entries in each subarray. Any any that is not a date is assigned in the destination array in the subarray corresponding to its date and with its own current key.




回答3:


I believe this solution will work for you:

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

Output

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
        )

)

check output at: https://3v4l.org/NvLB8




回答4:


Another approach (quick & dirty) making use of an arrays internal pointer:

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

This of course only works with the given array structure.




回答5:


Another perfect usage example for the PHP function 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()
);

The question is not clear. What is the expected result if one key (AAA f.e) is present on two or more dates? This answer keeps only the last value associated with it.




回答6:


I definitely wouldn't recommend any techniques that involve more than one loop -- this process can certainly be performed in a single loop.

If you like language construct iteration, use a foreach() loop: (Demo)

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

If you like to use functional programming and fewer global variables, use 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;
        },
        []
    )
);

These techniques unconditionally push data into the subarray with the key based on the date column value.

The above technique will work consistently even if the order of your subarray elements changes.

The ?? (null coalescing operator) is to ensure that array_merge() always has an array in the first parameter -- if processing the first occurrence of a given date, you simply merge the current iteration's data (what's left of it after unset() removes the date element) with an empty array.



来源:https://stackoverflow.com/questions/45834118/group-and-merge-subarray-data-based-on-one-column-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!