Here are a few considerations:

  • You might rename $value to $subarray to be more literal about the data that it holds.

  • Because there is no need to modify the subarray, you can access the lone value by calling current() instead of array_pop().

  • You can combine your nested conditional logic into one and eliminate the declaration of $data by assigning directly to $temp[$groupValue][]

Just before the return:

if (!$preserveSubArrays && count(key]) == 1) {
    $temp[$groupValue][] = current(key]);
} else {
    $temp[$groupValue][] = key];
}

I guess I should also point out that your function makes a few assumptions about the data being passed to it. There are a few ways to elicit Notices/Warnings from this function by passing an uncooperative array of data or grouping value. This may be a "tinfoil hat" observation for the scope of your question, but I thought I'd acknowledge it.

Generally, it looks likes a good cover-all function for the many StackOverflow questions that seek what this function can provide.

p.s. In a previous comment that I have since deleted, I suggested replacing unset() with another function. This was before I fully understood what this function was doing. I toyed with an approach that used array_diff_key(), but there was no advantage. unset() is sure to be the most efficient way to modify the subarray (when necessary).


Years later "re-review":

  • Declare the argument and return data types to make your method a bit more strict and easier to maintain.
  • Use square brace syntax for declaring an array -- it is just more concise and consistent with other square brace syntax used for pushing elements.
  • if(!array_key_exists($groupValue, $temp)) { $temp[$groupValue] = array(); } is unnecessary because in php you don't need to instantiate an array before you push elements into it using [] syntax. BUT, it makes good sense to check if a given row actually contains the grouping column -- else you will be trying to access an undefined key.
  • Obey PSR-12 coding recommendations.
  • Endeavor to remove all single-use variables unless they improve the readability/comprehensibility of your script.
  • When accessing the potentially unset grouping values, reliably find it using the undisturbed original array (not the copy being iterated).

Suggested rewrite:

public function groupArray(
    array $arr,
    string|int $group,
    bool $preserveGroupKey = false,
    bool $preserveSubArrays = false
): array {
    $result = [];
    foreach (key => $row) {
        if (!key_exists($group, $row)) {
            throw new Exception("Could not group by $group on row with key $key");
        }
        if (!$preserveGroupKey) {
            unset(group]);
        }
        $result[key][$group]][] = !$preserveSubArrays && count($row) === 1
            ? current(row;
    }
    return $result;
}
Answer from mickmackusa on Stack Exchange
🌐
PHP
php.net › manual › en › function.array-column.php
PHP: array_column - Manual
<?php $records = array( array( 'id' => 2135, 'first_name' => 'John', 'last_name' => 'Doe', 'company_id' => 1, ), array( 'id' => 3245, 'first_name' => 'Sally', 'last_name' => 'Smith', 'company_id' => 1, ), array( 'id' => 5342, 'first_name' => 'Jane', 'last_name' => 'Jones', 'company_id' => 1, ), array( 'id' => 5623, 'first_name' => 'Peter', 'last_name' => 'Doe', 'company_id' => 2, ) ); $first_names = array_column($records, 'first_name', 'company_id'); print_r($first_names); ?> The above example will output: <?php Array ( [1] => Jane [2] => Peter ) ?> To group values by the same `index_key` in a
Top answer
1 of 2
6

Here are a few considerations:

  • You might rename $value to $subarray to be more literal about the data that it holds.

  • Because there is no need to modify the subarray, you can access the lone value by calling current() instead of array_pop().

  • You can combine your nested conditional logic into one and eliminate the declaration of $data by assigning directly to $temp[$groupValue][]

Just before the return:

if (!$preserveSubArrays && count(key]) == 1) {
    $temp[$groupValue][] = current(key]);
} else {
    $temp[$groupValue][] = key];
}

I guess I should also point out that your function makes a few assumptions about the data being passed to it. There are a few ways to elicit Notices/Warnings from this function by passing an uncooperative array of data or grouping value. This may be a "tinfoil hat" observation for the scope of your question, but I thought I'd acknowledge it.

Generally, it looks likes a good cover-all function for the many StackOverflow questions that seek what this function can provide.

p.s. In a previous comment that I have since deleted, I suggested replacing unset() with another function. This was before I fully understood what this function was doing. I toyed with an approach that used array_diff_key(), but there was no advantage. unset() is sure to be the most efficient way to modify the subarray (when necessary).


Years later "re-review":

  • Declare the argument and return data types to make your method a bit more strict and easier to maintain.
  • Use square brace syntax for declaring an array -- it is just more concise and consistent with other square brace syntax used for pushing elements.
  • if(!array_key_exists($groupValue, $temp)) { $temp[$groupValue] = array(); } is unnecessary because in php you don't need to instantiate an array before you push elements into it using [] syntax. BUT, it makes good sense to check if a given row actually contains the grouping column -- else you will be trying to access an undefined key.
  • Obey PSR-12 coding recommendations.
  • Endeavor to remove all single-use variables unless they improve the readability/comprehensibility of your script.
  • When accessing the potentially unset grouping values, reliably find it using the undisturbed original array (not the copy being iterated).

Suggested rewrite:

public function groupArray(
    array $arr,
    string|int $group,
    bool $preserveGroupKey = false,
    bool $preserveSubArrays = false
): array {
    $result = [];
    foreach (key => $row) {
        if (!key_exists($group, $row)) {
            throw new Exception("Could not group by $group on row with key $key");
        }
        if (!$preserveGroupKey) {
            unset(group]);
        }
        $result[key][$group]][] = !$preserveSubArrays && count($row) === 1
            ? current(row;
    }
    return $result;
}
2 of 2
3

Just in case you are looking for such a functionality for your database wrapper, note that it already exists in PDO, which can group results for you right off the query, thanks to the PDO::FETCH_GROUP constant that can be used in fetchAll() function.

So you can get your arrays out of the box. For the first one you could combine this mode with PDO::FETCH_COLUMN:

$data = $db->run("SELECT `group`, name FROM users")
           ->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_COLUMN);

whereas for the second one it would be just

$data = $db->run("SELECT `group`, name FROM users")->fetchAll(PDO::FETCH_GROUP);

Note that such a verbose notation is better then anonymous function parameters for readability.

Put yourself in place of someone who would be reading your code. For example, imagine you are reading a like this

combineArray($arr, "group", false, true);

-- would you be able to tell what does this particular call do?

So it's at least better to define named constants that contain your booleans as values and make this call

 groupArray($arr, "group", GR_PRESERVE_KEYS, GR_PRESERVE_SUBARRAYS);

having GR_DROP_KEY and GR_DISBAND_SUBARRAYS in reserve. Or consider just a single parameter with bitmask arguments, just like in many PHP functions.

🌐
GitHub
gist.github.com › mcaskill › baaee44487653e1afc0d
PHP : Groups an array by a given key · GitHub
ErrorException (E_WARNING) call_user_func_array() expects parameter 1 to be a valid callback, function 'array_group_by' not found or invalid function name ... This may be a very late answer, but if you want to use this as a static method you should modify line 64 into $grouped[$key] = call_user_func_array(['self', 'array_group_by'], $params);
🌐
PHP Freaks
forums.phpfreaks.com › php coding › php coding help
php how to group a multidimensional array by a particular value? - PHP Coding Help - PHP Freaks
February 3, 2010 - Hopefully, I can explain this correctly... I have a multidimensional array and am trying to group them according to the value of one the keys. So, I'm trying to group them by level, but I won't actually know the level beforehand. So, it's not like I can put it in a for loop and say while $i
🌐
Packagist
packagist.org › packages › mcaskill › php-array-group-by
mcaskill/php-array-group-by - Packagist.org
$key — The key to group or split by. Can be a string, an integer, a float, or a callback. If the key is NULL, the iterated element is skipped. If the key is a callback, it must return a valid key from the array. ... Returns a multidimensional array, with each dimension containing elements grouped by the passed key(s).
🌐
SitePoint
sitepoint.com › php
How to group and get average values from PHP multidimensional array - PHP - SitePoint Forums | Web Development & Design Community
November 22, 2014 - I am trying to figure out a way I can group all of the items with a similar date in the array below and find the average price for the date based on the corresponding price from the array below. Array ( [0] => Array ( [dates] => Array ( [0] => 2015-05-04 [1] => 2015-05-04 [2] => 2015-05-04 [3] => 2015-05-04 [4] => 2015-05-04 [5] => 2015-...
Find elsewhere
🌐
Stack Overflow
stackoverflow.com › questions › 18832219 › grouping-multi-dimensional-array-in-php
grouping multi-dimensional array in PHP - Stack Overflow
I have the first level of grouping working: $groups = array(); foreach($inv_h as $item) { $groups[$item['org']][] = $item; } ... If these values come from a database it's much easier to sort them with an ORDER BY clause.
🌐
YouTube
youtube.com › hey delphi
PHP : How to group a multidimensional array by a particular subarray value? - YouTube
PHP : How to group a multidimensional array by a particular subarray value?To Access My Live Chat Page, On Google, Search for "hows tech developer connect"As...
Published   May 1, 2023
Views   2
🌐
IQCode
iqcode.com › code › php › php-group-multidimensional-array-by-value
php group multidimensional array by value Code Example
function arraySort($input,$sortkey){ foreach ($input as $key=&gt;$val) $output[$val[$sortkey]][]=$val; return $output; }
Top answer
1 of 2
1

I hope this helps

public function array_group_by($array, $key) {

    if (is_null($key)) return $array;
    $result = array();

    foreach ($array as $item) {
        $group_key = $item[$key];
        if (!array_key_exists($group_key, $result)) {
            $result[$group_key] = array();
        }
        $result[$group_key][] = $item;
    }

    return $result;
}

so you can call array_group_by($proplist, 'state'); which should give you the required result as an array.

var_dump(array_group_by($proplist,'state');

should output

array (size=3)
  'GA' => 
    array (size=2)
      0 => 
        array (size=5)
          'name' => string 'Store #1' (length=8)
          'address' => string '123 Example St' (length=14)
          'city' => string 'Smyrna' (length=6)
          'state' => string 'GA' (length=2)
          'zip' => string '11111' (length=5)
      1 => 
        array (size=5)
          'name' => string 'Store #4' (length=8)
          'address' => string '111 Someplace Rd' (length=16)
          'city' => string 'Atlanta' (length=7)
          'state' => string 'GA' (length=2)
          'zip' => string '22222' (length=5)
  'VA' => 
    array (size=1)
      0 => 
        array (size=5)
          'name' => string 'Store #2' (length=8)
          'address' => string '666 Anywhere Rd' (length=15)
          'city' => string 'Bristol' (length=7)
          'state' => string 'VA' (length=2)
          'zip' => string '33333' (length=5)
  'NC' => 
    array (size=1)
      0 => 
        array (size=5)
          'name' => string 'Store #3' (length=8)
          'address' => string '123 Any Street' (length=14)
          'city' => string 'Bristol' (length=7)
          'state' => string 'NC' (length=2)
          'zip' => string '44444' (length=5)

You can also find a working example here https://eval.in/98276

2 of 2
0

As far as I know, there are no grouping build in functions to archive this. So the only way is to do it manually, like so:

$result = array();
foreach ($proplist as $data) {
  $id = $data['state'];
  if (isset($result[$id])) {
     $result[$id][] = $data;
  } else {
     $result[$id] = array($data);
  }
}

var_dump($result);

Or if you want only to sort those elements:

foreach ($proplist as $key => $row) {
    $states[$key]  = $row['state']; 
}
array_multisort($states, SORT_ASC, $proplist);