Search code examples
phparraysmultidimensional-arraymapping

Copy first level keys of a 2d array as a new column of each row


Assuming a 2d array as input, how can each first level key be copied as a new element in its second level row?

Sample input:

$members = [
    'myname' => ['userid' => 52, 'age' => 46],
    'isname' => ['userid' => 22, 'age' => 47],
    'yourname' => ['userid' => 47, 'age' => 85]
];

Desired result:

[
    'myname' => ['userid' => 52, 'age' => 46, 0 => 'myname'],
    'isname' => ['userid' => 22, 'age' => 47, 0 => 'isname'],
    'yourname' => ['userid' => 47, 'age' => 85, 0 => 'yourname'],
]

After fixing some typos, the following script works, but how else can this be achieved?

foreach ($members as $key => $item) {
  array_push($members[$key], $key);
}

This question was stimulated by array_push not working in foreach loop which suffered from multiple typos and was closed accordingly.


Solution

    • A body-less foreach() loop signature can ignore all pre-existing row elements and solely create a reference to the new column and since the key variable is accessed after the value variable, the $key value is assigned to the referenced column. In my opinion, this is the most elegant, non-functional-style script, but it might not be the most intuitive solution for all developers. Demo

      foreach ($members as $col => [&$col]);
      var_export($members);
      

      The 0 column/key is implied by omitting 0 => before the reference declaration inside of the square braced expression. If you want to give the new column a key other than 0, then write that in the array destructuring expression. Demo



    • The above snippet is more elegant than declaring the temporary row variable which doesn't need to be used to affect the original array. Demo

      foreach ($members as $col => $row) {
           $members[$col][] = $col;
      }
      var_export($members);
      


    • Using array_walk() serves the same purpose as a foreach() with its ability to access rows and first level keys, but it doesn't return a payload, so modifying data by reference is the only way. Demo

      array_walk($members, fn(&$row, $col) => $row += [$col]);
      var_export($members);
      


    • Probably least attractive versus earlier snippets, you could use a functional-style with array_reduce() to append the new column to each row. Demo

      var_export(
           array_reduce(
               array_keys($members),
               fn($result, $k) => $result + [$k => $members[$k] + [$k]],
               []
           )
      );