0


I have a array that looks like this:

$array = [
    ["444", "0081"],
    ["449", "0081"],
    ["451", "0081"],
    ["455", "2100"],
    ["469", "2100"]
];

I need to group as a new array that looks like:

array (
  0 => 
  array (
    0 => '444,449,451',
    1 => '0081',
  ),
  1 => 
  array (
    0 => '455,469',
    1 => '2100',
  ),
)

I'd tried many scripts, but with no success.

function _group_by($array, $key) {
    $return = array();
    foreach($array as $val) {
        $return[$val[$key]][] = $val;
    }
    return $return;
}
$newArray = _group_by($array, 1); // (NO SUCCESS)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Roy Bogado
  • 4,299
  • 1
  • 15
  • 31
  • There are literally dozens of similar questions already answered on SO. Search for [`array_reduce()`](http://php.net/manual/en/function.array-reduce.php). – axiac Aug 30 '17 at 16:09
  • Related: [Group rows of a multidimensional array and form comma-separated values within each group](https://stackoverflow.com/q/14255369/2943403) and [PHP: Merging adjacent values if duplicates found in a multidimensional array](https://stackoverflow.com/q/42928987/2943403) and [Group by a multidimensional array in PHP and concatenate results with comma (without creating unnecessary commas)](https://stackoverflow.com/q/46723327/2943403) – mickmackusa Jan 18 '23 at 00:54

2 Answers2

2

There should be more elegant solutions, but simplest one I can think of would be this.

// The data you have pasted in the question
$data = []; 
$groups = [];

// Go through the entire array $data
foreach($data as $item){
    // If the key doesn't exist in the new array yet, add it       
    if(!array_key_exists($item[1], $groups)){
        $groups[$item[1]] = [];
    }

    // Add the value to the array
    $groups[$item[1]][] = $item[0];
}

// Create an array for the data with the structure you requested
$structured = [];
foreach($groups as $group => $values){
    // With the array built in the last loop, implode it with a comma
    // Also add the 'key' from the last array to it ($group)
    $structured[] = [implode(',', $values), $group];
}

I haven't tested this but something similar should do the trick. This simply goes through the given array and collects all entries in a structurized manner (so $groups variable will contain an array entry for each group sharing a key, and the key will correspond to the 2nd item in each item within the given array). From there it's just about restructuring it to get the format you have requested.

http://php.net/manual/en/control-structures.foreach.php

Kerwin Sneijders
  • 750
  • 13
  • 33
Giedrius
  • 1,370
  • 3
  • 14
  • 37
0

Writing two loops is too much effort for this task. Use isset() with temporary keys applied to your output array as you iterate. When finished grouping the data, reindex the output with array_values().

Code (Demo)

$array = [
    ["444", "0081"],
    ["449", "0081"],
    ["451", "0081"],
    ["455", "2100"],
    ["469", "2100"]
];

foreach ($array as $row) {
    if (!isset($result[$row[1]])) {
        $result[$row[1]] = $row;  // first occurrence of group, save whole row
    } else {
        $result[$row[1]][0] .= ',' . $row[0];  // not first occurrence, concat first element in group
    }
}
var_export(array_values($result));

Or avoid the temporary associative arrays in the result array by using an array of references. (Demo)

$result = [];
foreach ($array as $row) {
    if (!isset($ref[$row[1]])) {
        $ref[$row[1]] = $row;
        $result[] = &$ref[$row[1]];
    } else {
        $ref[$row[1]][0] .= ',' . $row[0];
    }
}
var_export($result);

Or use array_reduce() to enjoy a functional-style technique. (Demo)

var_export(
    array_values(
        array_reduce(
            $array,
            function($result, $row) {
                if (!isset($result[$row[1]])) {
                    $result[$row[1]] = $row;
                } else {
                    $result[$row[1]][0] .= ',' . $row[0];
                }            
                return $result;
            }
        )
    )
);

All will output:

array (
  0 => 
  array (
    0 => '444,449,451',
    1 => '0081',
  ),
  1 => 
  array (
    0 => '455,469',
    1 => '2100',
  ),
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136