2

I need to flatten a multidimensional array, but not flattening the last level.

For example, consider the following array

$array = [
    1 => [
        1 => [
            'anna',
            'alice'
        ],
        2 => [
            'bob',
            'bartold'
        ]
    ],
    2 => [
        1 => [
            'carol'
        ],
        2 => [
            'david'
        ]
    ]
];

The following code

$result = [];

$iterator = new \RecursiveIteratorIterator(
    new \RecursiveArrayIterator($array)
);

foreach ($iterator as $row) {
    $result[] = $row;
}

returns the following array

array(6) {
  [0]=>
  string(4) "anna"
  [1]=>
  string(5) "alice"
  [2]=>
  string(3) "bob"
  [3]=>
  string(7) "bartold"
  [4]=>
  string(5) "carol"
  [5]=>
  string(5) "david"
}

What I would like to obtain is the following:

[
    1 => [
        'anna',
        'alice'
    ],
    2 => [
        'bob',
        'bartold'
    ],
    3 => [
        'carol'
    ],
    4 => [
        'david'
    ]
];

not flattening the last level of the array. Is there an easy way to obtain this?

Possibly I would like to use iterators.

If you want you could try to play with this.

3
  • did you try with array_walk_recursive? php.net/manual/en/function.array-walk-recursive.php Commented Apr 15, 2015 at 15:16
  • @briosheje yes, I tried, the result is exactly the same as the one that I get with the code I posted Commented Apr 15, 2015 at 15:17
  • You can't get what you want for two reasons: 1) The nesting logic of the node [1] is different from node [2]. 2) you're somehow assigning new keys that cannot be logically recreated in a recursive loop (keys 1,2,3,4 in the output), because it is recursive. I would personally suggest you to either perform a nested foreach loop or to just implement an ad-hoc function. Commented Apr 15, 2015 at 15:54

2 Answers 2

2

You can flatten the array recursively while on each element you would look ahead if it contains subarrays and change merging based on it:

<?php

function flattenArrayWithLookAhead($include = array()) {
  $new = array();

  foreach($include as $item) {
    if(is_array($item)) {
      $containsArrays = array_reduce($item, function ($carry, $current) {
        if(is_array($current) || $carry === true) return true;
        else return false;
      });

      if($containsArrays) $new = array_merge($new, flattenArrayWithLookAhead($item));
      else $new[] = $item;
    } else {
      $new[] = $item;
    }
  }

  return $new;
}

$array = flattenArrayWithLookAhead($array);

online TEST

(NOTE: I'm sure the function can be simplified but my love for recursive functions is currently at its minimum.)

Sign up to request clarification or add additional context in comments.

Comments

1

Remember that recursive iterators always walk the data structure to return the data nodes, not the preceding structure. To keep the structure as well you could do a nested foreach

$newdata = array();
foreach($data as $group) {
    foreach($group as $set) {
        $newdata[] = $set;
    }
}

1 Comment

the problem with the nested foreach is that if I need to add a nesting level near the root, my code would not work anymore. I guess that the only solution would be to use a recursive function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.