Group 2d array data using column value to create a 3d array
Asked Answered
A

8

36

I have a multidimensional array and am trying to group them according to the value in a specific column.

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 < 7, because I won't know that 7 is the maximum value for the level key, and frankly, I'm not sure that's how I would need to do it even if I did.

[
    ['cust' => 'XT8900', 'type' => 'standard', 'level' => 1],
    ['cust' => 'XT8944', 'type' => 'standard', 'level' => 1],
    ['cust' => 'XT8922', 'type' => 'premier', 'level' => 3],
    ['cust' => 'XT8816', 'type' => 'permier', 'level' => 3],
    ['cust' => 'XT7434', 'type' => 'standard', 'level' => 7],
]

Desired result:

Array (

   [1] => Array (
          [0] => Array (
                    [cust] => XT8900
                    [type] => standard
                    )
          [1] => Array (
                    [cust] => XT8944
                    [type] => standard
                    )
          )

   [3] => Array (
          [2] => Array (
                 [cust] => XT8922
                 [type] => premier
                 )

          [3] => Array (
                 [cust] => XT8816
                 [type] => permier
                 )
          )

   [7] => Array (
          [4] => Array (
                 [cust] => XT7434
                 [type] => standard
                 )
          )
)
Approval answered 3/2, 2010 at 4:9 Comment(0)
S
12

You need to group them by level first

Use foreach to loop into array check if the level is the same with the previous item then group it with that array

  $templevel=0;   

  $newkey=0;

  $grouparr[$templevel]="";

  foreach ($items as $key => $val) {
   if ($templevel==$val['level']){
     $grouparr[$templevel][$newkey]=$val;
   } else {
     $grouparr[$val['level']][$newkey]=$val;
   }
     $newkey++;       
  }
print($grouparr);

The output of print($grouparr); will display like the format you hoped for

You can also try to

print($grouparr[7]);

Will display

 [7] => Array (
      [4] => Array (
             [cust] => XT7434
             [type] => standard
             )
      )

Or

print($grouparr[3]);

Will display

[3] => Array (
      [2] => Array (
             [cust] => XT8922
             [type] => premier
             )

      [3] => Array (
             [cust] => XT8816
             [type] => permier
             )
      )
Synectics answered 3/2, 2010 at 5:27 Comment(1)
I think the 'if' clause in your code above is redundant, since the line " $grouparr[$val['level']][$newkey]=$val; " works for all cases. In other words, this line holds true also for the case that '$templevel' is equal to '$val['level']'. So, in that case, the code would just be: $templevel=0; $newkey=0; foreach ($items as $key => $val) { $grouparr[$val['level']][$newkey]=$val; $newkey++; } print($grouparr);Ypsilanti
T
48

Best way, if you have control over building the initial array, is just set things up like that at the start as you add entries.

If not then build a temporary array to sort:

foreach ($input_arr as $key => &$entry) {
    $level_arr[$entry['level']][$key] = $entry;
}

Leaves you with the form you wanted and everything referenced together.

Build the array like that in the first place though if at all possible.

Tonjatonjes answered 3/2, 2010 at 5:33 Comment(2)
I don't understand the benefit of making $entry a reference.Kyrstin
@Kyrstin foreach makes a copy of the array it's iterating over in some circumstances. Being explicit about using a reference means you can be sure it's not copying what could be a huge input array. I don't know if that micro-optimisation is relevant in 2023, the world was much younger when I originally wrote this answer :)Tonjatonjes
S
12

You need to group them by level first

Use foreach to loop into array check if the level is the same with the previous item then group it with that array

  $templevel=0;   

  $newkey=0;

  $grouparr[$templevel]="";

  foreach ($items as $key => $val) {
   if ($templevel==$val['level']){
     $grouparr[$templevel][$newkey]=$val;
   } else {
     $grouparr[$val['level']][$newkey]=$val;
   }
     $newkey++;       
  }
print($grouparr);

The output of print($grouparr); will display like the format you hoped for

You can also try to

print($grouparr[7]);

Will display

 [7] => Array (
      [4] => Array (
             [cust] => XT7434
             [type] => standard
             )
      )

Or

print($grouparr[3]);

Will display

[3] => Array (
      [2] => Array (
             [cust] => XT8922
             [type] => premier
             )

      [3] => Array (
             [cust] => XT8816
             [type] => permier
             )
      )
Synectics answered 3/2, 2010 at 5:27 Comment(1)
I think the 'if' clause in your code above is redundant, since the line " $grouparr[$val['level']][$newkey]=$val; " works for all cases. In other words, this line holds true also for the case that '$templevel' is equal to '$val['level']'. So, in that case, the code would just be: $templevel=0; $newkey=0; foreach ($items as $key => $val) { $grouparr[$val['level']][$newkey]=$val; $newkey++; } print($grouparr);Ypsilanti
G
7

Here is the solution I landed on for an identical problem, wrapped as a function:

function arraySort($input,$sortkey){
  foreach ($input as $key=>$val) $output[$val[$sortkey]][]=$val;
  return $output;
}

To sort $myarray by the key named "level" just do this:

$myArray = arraySort($myArray,'level');

Or if you didn't want it as a function, just for a one time use, this would create $myNewArray from $myArray grouped by the key 'level'

foreach ($myArray as $key=>$val) $myNewArray[$val['level']][]=$val;
Gynaeceum answered 15/3, 2012 at 14:54 Comment(2)
this is such a useful answer. I'm trying to use this but to have $val be a unique value. Suggestions?Carpophagous
This answer doesn't not provide the OP's desired output because it is not incrementing the subarray keys. Proof: sandbox.onlinephpfunctions.com/code/…Kyrstin
K
7
function group_assoc($array, $key) {
    $return = array();
    foreach($array as $v) {
        $return[$v[$key]][] = $v;
    }
    return $return;
}

//Group the requests by their account_id
$account_requests = group_assoc($requests, 'account_id');
Kremenchug answered 27/8, 2012 at 15:9 Comment(1)
Not only does this post do a poor job of explaining itself, it doesn't increment the subarray keys as required by the OP. Furthermore, it doesn't even dignify the key values from the question -- account_id has nothing to do with this question. For all of these reasons, I am surprised that it has gained so many upvotes and I have downvoted as a matter of principle. Proof: sandbox.onlinephpfunctions.com/code/… I care about the quality of old content on this site, because I use it to close new questions when appropriate.Kyrstin
K
1

To generate the question's exact desired output from the sample input, pull/pop the last value from each row, use that value as the first level grouping key. Then use the original first level index as the second level key. Then push the two remaining elements into the group's subset.

Code: (Demo)

$result = [];
foreach ($array as $key => $row) {
    $result[array_pop($row)][$key] = $row;
}
var_export($result);

For functional style syntax, use array_reduce(). (Demo)

var_export(
    array_reduce(
        array_keys($array),
        function($result, $key) use ($array) {
            $result[array_pop($array[$key])][$key] = $array[$key];
            return $result;
        }
    )
);
Kyrstin answered 21/1, 2023 at 9:26 Comment(0)
S
0
  $result = array();
    foreach ($yourArrayList as $data) {
        $id = $data['level'];
        if (isset($result[$id])) {
            $result[$id][] = $data;
        } else {
            $result[$id] = array($data);
        }
    }
Stanfield answered 18/10, 2014 at 6:13 Comment(1)
Code-only answers are low value on StackOverflow because they do a poor job of educating the OP and future researchers -- every answer (even basic ones) should include some sort of explanation about how the solution works and why it is advisable. This answer does NOT provide the desired output as dictated by the question because it does not increment the subarray keys. Proof: sandbox.onlinephpfunctions.com/code/…Kyrstin
M
0

Best ans.

    $levels = array_unique(array_column($records, 'level'));

    $data = array();

    foreach($records as $key => $value){ 

    $data[$levels[array_search($value['level'],$levels )]][] = $value ; 

    }

    print_r($data); 
Multiplication answered 18/12, 2018 at 7:25 Comment(1)
Code-only answers are discouraged. Please click on edit and add some words summarising how your code addresses the question, or perhaps explain how your answer differs from the previous answer/answers. ThanksTish
C
-2
function _group_by($array,$key,$keyName)
    {
          $return = array();

          foreach($array as $val) {
              $return[$keyName.$val[$key]][] = $val;
          }
         return $return;

    }  //end of function
Craw answered 28/5, 2016 at 10:2 Comment(1)
This answer supplies no logic nor explanation. I don't have any idea what $key and $keyName are meant to hold. I have downvoted this answer because I can't make sense of it and I don't know what values to feed the function.Kyrstin

© 2022 - 2024 — McMap. All rights reserved.