1

I need to unset elements from arrays that are nested into another array, in a way that only the first N elements would be kept (N being predefined). Only elements that have a numerical index should be affected.

Input array:

Array
(
    [0] => Array (
        [a] => 'w'
        [b] => Array (
             [0]=> 'x'
             [1]=> 'x'
             [2]=> 'x'
        )
    )               
    [1] => Array (
        [a] => 'y'
    )
    [2] => Array (
        [0] => 'z'
        [1] => 'z'
        [2] => 'z'
    )
)

Desired output (with N=2):

Array
(
    [0] => Array (
        [a] => 'w'
        [b] => Array (
             [0]=> 'x'
             [1]=> 'x'
        )
    )               
    [1] => Array (
        [a] => 'y'
    )
)

Based on the above definition, only [0][b][2] and [2] got unset because they had a numerical index and because they both represnted the 3rd element of their respective array.

2
  • How do you wish to nest them? Am I correct in assuming that 10 levels of nesting are possible? Or is your example also the maximum amount of nesting? Perhaps giving a concrete example of what it does can give a clear image of your code. Commented Jun 4, 2011 at 9:31
  • There aren't any limitations to the levels of nesting. There may be 10 levels, there may be more, there may be less, hence my initial impression that I may have to use array_walk_recursive to do the job, but waiting for more feedback in case there is a better way to do it. Commented Jun 4, 2011 at 9:35

5 Answers 5

5

Haven't tested but something like this might work.

function myFunc(&$array){
foreach($array as $key=>&$value){
 if(is_array($value)){
   myFunc($value);
 }
 if(is_numeric($key) && $key > 1){
   unset($array[$key]);
 }
}
}

About array_walk. php.net says:

the programmer cannot add, unset or reorder elements. If the callback does not respect this requirement, the behavior of this function is undefined, and unpredictable.

2
  • that looks good for unset an element of a particular array. Now I need to find a way to recursively get all the nested arrays of an array. Commented Jun 4, 2011 at 9:50
  • 1
    the function I wrote does it recursively. if a value is a function it calls itself recursively. Commented Jun 4, 2011 at 9:52
1

Write yourself a function that does exactly what you want. Then document the function so if you need to use it in about two weeks, you might want to know what exactly that function is doing.

I say this because the data structure you want to handle seems to be very specific. So it's worth to encapsulate it in a function on it's own to hide away the complexity. Name the function properly.

Inside the function you can process the data in the various ways and with the various conditions you need to formulate. Parameters from the outside can be passed as function parameters. The return value is the result you aim to achieve.

1

This worked for me, perhaps not the cleanest code.

$array = array
(
    array(
        'a' => 'w',
        'b' => array('x','x','x')
    ),
    array(
        'a' => 'y'
    ),
    array(
        'z','z','z'
    )
);

function recurse_and_strip ($array, &$size=2)
{
    foreach ($array as $key => &$element)
    {
        if (is_hash($element))
        {
            $element = recurse_and_strip($element,$size);
        } else if (is_array($element))
        {
            $deletefrom = false;
            // now the tricky part.. see how many must be deleted
            for ($i=0; $i < count($element); $i++ )
            {
                if ($size == 0)
                {
                    echo "Delete from " . $i;
                    $deletefrom = $i;
                    break 1;
                }
                $size--;
            }
            if ($deletefrom !== false)
            {
                if ($deletefrom == 0)
                {
                    unset($array[$key]);
                } else {
                    array_splice($element,$deletefrom);
                }
            }
        }
    }
    return $array;
}

// source http://www.benjaminkeen.com/?p=23
function is_hash($var)
{
  if (!is_array($var))
    return false;

  return array_keys($var) !== range(0,sizeof($var)-1);
}

var_dump(recurse_and_strip($array,2));
3
  • works for me, altough I think your var_dump line is incorrect, as 2 is given as a parameter to var_dump and not recurse_and_strip as it should. Thanks a lot anyway. Commented Jun 4, 2011 at 12:10
  • unfortunately, when testing on an array with 3 nesting levels it doesn't work anymore. Commented Jun 4, 2011 at 12:15
  • Can you show me the example you're using? Here it also works with 3 nesting levels.. also, what's the error? Commented Jun 4, 2011 at 14:13
1

array_walk_recursive itself cannot achieve what you want. Even though you can pass array by reference, unsetting the variable in the callback will only unset it in that scope.

However, you can use walk_recursive_remove function:

/**
 * http://uk1.php.net/array_walk_recursive implementation that is used to remove nodes from the array.
 *
 * @param array The input array.
 * @param callable $callback Function must return boolean value indicating whether to remove the node.
 * @return array
 */
function walk_recursive_remove (array $array, callable $callback) {
    foreach ($array as $k => $v) {
        if (is_array($v)) {
            $array[$k] = walk_recursive_remove($v, $callback);
        } else {
            if ($callback($v, $k)) {
                unset($array[$k]);
            }
        }
    }

    return $array;
}

You will need to implement your own logic using the $callback to unset the specific values.

0

Here's a more general solution to modifying the array to which the leaf belongs. You can unset the current key, or add siblings, etc.

/**
 * Modified version of array_walk_recursive that passes in the array to the callback
 * The callback can modify the array or value by specifying a reference for the parameter.
 *
 * @param array The input array.
 * @param callable $callback($value, $key, $array)
 */
function array_walk_recursive_array(array &$array, callable $callback) {
    foreach ($array as $k => &$v) {
        if (is_array($v)) {
            array_walk_recursive_array($v, $callback);
        } else {
            $callback($v, $k, $array);
        }
    }
}

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.