3

I've been having a little trouble trying to flatten arrays in a specific way.

Here is a print_r view of the array I want to flatten:

Array
    (
        [1] => Array
            (
                [8] => 1
                [9] => 2
                [10] => Array
                    (
                        [15] => Array
                            (
                                [22] => 1
                            )

                        [21] => 2
                    )

                [11] => Array
                    (
                        [16] => Array
                            (
                                [23] => 1
                            )

                    )

            )

        [2] => Array
            (
                [12] => 1
            )

        [3] => Array
            (
                [13] => 1
            )

        [4] => Array
            (
                [14] => 1
            )

        [5] => 5
        [6] => 6
        [7] => 7
    )

What I'm attempting to create is an array which keeps the above indexes, but the value is equal to it's position in the array, much like the original index (starting from zero).

Here is the desired result:

Array
    (
        [1] => 1
        [2] => 2
        [3] => 3
        [4] => 4
        [5] => 5
        [6] => 6
        [7] => 7
        [8] => 1
        [9] => 2
        [10] => 3
        [11] => 4
        [12] => 1
        [13] => 1
        [14] => 1
        [15] => 1
        [16] => 1
        [21] => 2
        [22] => 2
        [23] => 1
    )

Knowingly, 17 to 20 are missing.

My function is as follows:

function array_flatten ($array) {
    $result                 = array ();
    $count                  = 1;
    while ($index = current($array)) {
        $result[key($array)] = $count;
        if (is_array($index)) {
            $result = array_merge(array_flatten($index), $result);
        }
        next($array);
        $count++;
    }
    return $result;
}

The line $result = array_merge(array_flatten($index), $result); appears to be the problems. It returns:

Array
(
    [1] => 1
    [2] => 2
    [3] => 3
    [4] => 4
    [5] => 5
    [6] => 6
    [7] => 7
)

However, if I run var_dump(array_flatten($index)); on the same line, it returns all the arrays I wish to merge to the $result variable.

array
  22 => int 1
array
  15 => int 1
  21 => int 2
array
  23 => int 1
array
  16 => int 1
array
  8 => int 1
  9 => int 2
  10 => int 3
  11 => int 4
array
  12 => int 1
array
  13 => int 1
array
  14 => int 1

It seems that that array_merge doesn't actually merge these arrays.

Is there something I am doing wrong? Any words of guidance are very much appreciated. Thank you.

Update

Solved!

The function which does the required is as follows:

function array_flatten($array, &$result = array()) {
    $count              = 1;
    foreach($array as $index => $value) {
        $result[$index] = $count;
        if(is_array($value)) {
            array_flatten($value, $result);
        }
        $count++;
    }
    return $result;
}
nderjung
  • 1,607
  • 4
  • 17
  • 38
  • How can 4 become 4 (`[4] => 4`) in your desired result? And please reduce your problem to the bare minimum as otherwise it's needlessly hard to follow and answer. – hakre Jul 15 '11 at 19:05
  • @hakre - it appears that `[4]=>4` because the the outmost array has 7elements, and the 4th one has index "4", @Aleks - you mention array_merge but I don't see it in your code anywhere. – timdev Jul 15 '11 at 19:12
  • @Aleks - also, it might be helpful if you provided some code to define your test array. – timdev Jul 15 '11 at 19:16
  • @timdev - Oh sorry, `array_flatten(array_flatten($index), $result);` is meant to be `array_merge(array_flatten($index), $result);`. – nderjung Jul 15 '11 at 19:37
  • @timdev: These array questions are calling for a [print_r converter](http://codepad.viper-7.com/kxIQ3c.php53). – hakre Jul 16 '11 at 04:15
  • @Aleks: Please move your solution to the problem from the question into an answer. – hakre Jul 16 '11 at 04:19

2 Answers2

2
function flatten_array($array, &$result) {
    foreach($array as $key => $value) {
        if(is_array($value)) {
            flatten_array($value, $result);
        } else {
            $result[$key] = $value;
        }
    }
}

To use this, check the sample code below:

$flattened = array();
$test = array(
      1 => 1
    , 3 => 2
    , array(2 => 4, 4 => 6)
    , 5 => 3
    , array(7 => 9, 8 => 7, 9 => 5)
);
flatten_array($test, $flattened);
// Now $flattened contains the flattened array
Arjan
  • 9,784
  • 1
  • 31
  • 41
  • It works! However, it throws up the following error: Warning: Missing argument 2 for array_flatten(), called in C:/file/update.php on line 11 and defined in C:/file/update.php on line 58. Line 58 is function definition, i.e. `function flatten_array($array, &$result)`. – nderjung Jul 15 '11 at 19:44
  • Solved it. `function flatten_array($array, &$result = array())` ;) Thanks again. – nderjung Jul 15 '11 at 20:03
  • If you want to use the flattened array (and you want to, otherwise you wouldn't bother to flatten it) you would need the value of the second parameter. So you would need to get an empty array and assign that as second parameter to the function. I'll update the answer to explain what I mean. – Arjan Jul 15 '11 at 20:15
  • Can you replace the `4 => 6` with `14 => 6` and then test for the return of element `4`? I think that one slipped through. – hakre Jul 15 '11 at 20:25
  • If you change `4 => 6` into `14 => 6` then `$flattened[4]` is not set and `$flattened[14]` is 6, just as you would expect. – Arjan Jul 15 '11 at 20:30
  • I did so as well but was told by OP that this is not the case. Because 4th element is at 4th position at the lowest level and should therefore be 4. See the comments below the question. But as long as Aleks does not complain, it's merely a coding puzzle. – hakre Jul 15 '11 at 20:56
  • @hakre - The lowest level of the first dimension is 7. The array indexes are a result of the number of values. The values are set by the position of the index in the array. That's why the first 7 items of the desired array match. When you move onto the second array, which the index continues to 8, the position is reset, which therefore sets the value to 1. – nderjung Jul 15 '11 at 22:34
  • 1
    I can only quote: *"@hakre - it appears that [4]=>4 because the the outmost array has 7elements, and the 4th one has index "4" [...] – timdev 3 hours ago"* compare with the original data in question. But leave it. ;) – hakre Jul 15 '11 at 22:37
0

After you have clarified your question, I was a bit surprised that you accepted an answer that does not return the data you expected. (I've now seen you added your solution to your question.)

What I did: I took the function from @Arjan as a base, and run it on the questions input data and compared it with the questions expected data. Then I worked on it a bit. This is what I came up with (as a result):

#   COMP  EXPECTED         . ACTUAL
#00:  ==  Array            . Array
#01:  ==  (                . (
#02:  ==      [1] => 1     .     [1] => 1
#03:  ==      [2] => 2     .     [2] => 2
#04:  ==      [3] => 3     .     [3] => 3
#05:  ==      [4] => 4     .     [4] => 4
#06:  ==      [5] => 5     .     [5] => 5
#07:  ==      [6] => 6     .     [6] => 6
#08:  ==      [7] => 7     .     [7] => 7
#09:  ==      [8] => 1     .     [8] => 1
#10:  ==      [9] => 2     .     [9] => 2
#11:  ==      [10] => 3    .     [10] => 3
#12:  ==      [11] => 4    .     [11] => 4
#13:  ==      [12] => 1    .     [12] => 1
#14:  ==      [13] => 1    .     [13] => 1
#15:  ==      [14] => 1    .     [14] => 1
#16:  ==      [15] => 1    .     [15] => 1
#17:  ==      [16] => 1    .     [16] => 1
#18:  ==      [21] => 2    .     [21] => 2
#19:  !=      [22] => 2    .     [22] => 1
#20:  ==      [23] => 1    .     [23] => 1
#21:  ==  )                . )
#22:  ==                   . 

It looks like that your expected data has a mistake for position 22.

This is the modified function (Demo):

function flatten_array($array, &$result = null) {
    $r = null === $result;
    $i = 0;
    foreach($array as $key => $value) {
        $i++;
        if(is_array($value)) {
            $result[$key] = $i;
            flatten_array($value, $result);
        } else {
            $result[$key] = $value;
        }
    }
    if ($r) {
        ksort($result);
        return $result;
    }
}

$actual = flatten_array($input);
hakre
  • 193,403
  • 52
  • 435
  • 836