1

I have a multidimensional array with variable number of levels of data. That is, I can't be sure how many iterations it will take to reach the Goal level, which is an array. Something like this:

[ 
    'key1' = 'value1',
    'key2' = 'value2',
    'key3' = [
        'key4' => [
            'key5' => 'value3'
            ],
        'key6' => 'value4'
    ],
    'key7' => [
        'Goal' => [
            'value5',
            'value6',
            'value7'
        ]
    ],
    'key8' => 'value8'],
    'key9' => [
        'Goal' => [
            'value9',
            'Foo',
            'value10'
        ]
    ]
]

I've tried both array_walk_recursive and ArrayIterator, but neither seems to quite get me where I need to be.

I need to go through each element of the array, and if the key is Goal examine the value (eg. the array that Goal holds) and see if that array contains the value Foo.

If Foo is found in the array, I need to add a new value (in addition to Foo-- so call it Bar) to the array and then continue, since there may be more Goals in the parent array.

Is there a way to "stop" the iterator when we find a Goal, without iterating further, and then do the array_search operation?

Edit: Trying somethings along these lines--

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array)); 
foreach($iterator as $key => $value)
{
   if($key == 'Goal')
   {
       if (is_array($value)) {
           if(array_search('Foo', $value)) {
               $value[] = 'Bar';
           }
       }
   }
}
3
  • SHow the code you currently have, it will at least clear up what you are trying to do Commented Sep 3, 2015 at 22:35
  • Something like this? eval.in/427733 Commented Sep 3, 2015 at 22:44
  • @RobbieAverill-- that's very nearly what is needed, but for two things-- 1) there can be multiple Goals in the array, and 2) I need the whole array returned, with the Bar additions, rather than just the Goal node. Thanks, you've gotten me much closer! Commented Sep 3, 2015 at 22:55

3 Answers 3

2

Not entirely sure if this is what you want to achieve but here's a solution which adds Bar to arrays nested in the Goal key:

$array = [
    'key1' => 'value1',
    'key2' => 'value2',
    'key3' => [
        'key4' => [
            'key5' => 'value3',
        ],
        'key6' => 'value4',
    ],
    'key7' => [
        'Goal' => [
            'value5',
            'value6',
            'value7',
        ],
    ],
    'key8' => 'value8',
    'key9' => [
        'Goal' => [
            'value9',
            'Foo',
            'value10',
        ],
    ],
];

function iterate(array $data, $goal = false)
{
    foreach ($data as $key => &$value) {
        if (is_array($value)) {
            $value = iterate($value, $key === 'Goal');

        } elseif (is_string($value)) {
            if (($value === 'Foo') && $goal) {
                $data[] = 'Bar';
                return $data;
            }
        }
    }

    return $data;
}

var_export(iterate($array));

The code generates the following output:

array (
  'key1' => 'value1',
  'key2' => 'value2',
  'key3' => 
  array (
    'key4' => 
    array (
      'key5' => 'value3',
    ),
    'key6' => 'value4',
  ),
  'key7' => 
  array (
    'Goal' => 
    array (
      0 => 'value5',
      1 => 'value6',
      2 => 'value7',
    ),
  ),
  'key8' => 'value8',
  'key9' => 
  array (
    'Goal' => 
    array (
      0 => 'value9',
      1 => 'Foo',
      2 => 'value10',
      3 => 'Bar',
    ),
  ),
)
Sign up to request clarification or add additional context in comments.

Comments

0

Iterators in my opinion would be weird to use in these kind of arrays... I would do it with something like this:

/*
    Usage:
            $wasFound = checkArray( "Goal", "Foo", $the_array);
            if ( $wasFound ) echo "Key and Value pair found in the array!";
            else { /* not found */ }
*/

function checkArray( $key_to_find, $value_to_find, $my_var, $last_key = NULL ) {
    $found = FALSE;

    if ( $last_key == $key_to_find && $my_var == $value_to_find )
        return TRUE;

    if ( $my_var == NULL )
        return FALSE;

    if ( is_array( $my_var ) ) {
        foreach ( $my_var AS $key => $value )
        {
            if ( $found ) {
                /* Do something else if needed when found */
                break;
            }

            $found = checkArray( $key_to_find, $value_to_find, $value, $key );
        }
    }

    return $found;
}

Comments

0

I agree that recursion is the way to do this. The problem with using array_walk_recursive is that you will not be able to see the Goal key, because as per the PHP documentation,

Any key that holds an array will not be passed to the function.

I am not really sure whether using a RecursiveIteratorIterator would be better than just writing a recursive function for it. A function for something like this should be fairly simple.

function addBar(&$array) {
    foreach ($array as $key => &$value) {
        if ($key === 'Goal') {
            if(array_search('Foo', $value)) {
                $value[] = 'Bar';
            }
        } elseif (is_array($value)) {
            addBar($value);
        }
    }
}

This function takes a reference to your array, so it will update your actual array rather than creating a copy with Bar added to each Goal.

Comments

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.