YsoL8
YsoL8

Reputation: 2214

Looking foward or back in a foreach loop

I am rendering navigation from a 2 dimensional array, using lists, as shown:

<ul> <li>parent 
<ul> <li>level 1</li> <li>level 1

<ul> <li>level 3</li> </ul>

</li> </ul>

<li> </ul>

</li> </ul>

Anyway to close the <li> and </ul> correctly I find I need some data from the next array in the foreach sequence. How can I retrieve this?

Upvotes: 0

Views: 3156

Answers (6)

YsoL8
YsoL8

Reputation: 2214

Found the answer staring me in the face. Retrieved the arrays I need like this:

foreach ($tree as $key => $link) {

$level = $link['level'];

$next_key = $key+1;

$prev_key = $key-1;

$next_array = $tree[$next_key];

$prev_array = $tree[$prev_key];

And then I could test the level property (indicating deph inside the navigation tree) with a buch of if statements to correctly insert the closing markup.

Messy code and I'm not proud of it, but it works!

Quite angry with myself for not seeing it before.

Upvotes: 0

akond
akond

Reputation: 16045

Not sure if this is what he asking for, but here's my shot

$list = array (
    'Home page' => null,
    'Articles'  => array (
        'Diving'    => null,
        'Skydiving' => null,
        'Stackoverflowing'  => null,
    ),
    'Nobody cares'  => array (
        'Hey'   => null,
        'It is just a test' => null,
    ),
);

function render_menu ($list)
{
    echo "<ul>\n";
    foreach ($y = new RecursiveArrayIterator ($list, RecursiveIteratorIterator::SELF_FIRST) as $key => $item)
    {
        if ($y->hasChildren ())
        {
            echo "<li>$key\n";
            render_menu ($item);
            echo "</li>\n";
        }
        else
        {
            echo "<li>$key</li>\n";
        }
    }
    echo "</ul>\n";
}

render_menu ($list);

Upvotes: 0

netcoder
netcoder

Reputation: 67735

Here's a solution:

$arr = array(1,2,3,4,5);

foreach ($arr as $foo) {
    if (empty($isrewind)) {
       reset($arr);
       $isrewind = true;
    }

    echo "node: $foo\n";

    $copy = $arr;   // make a copy of the array
    $next = next($copy);
    echo "next: $next\n";

    $copy = $arr;   // make a copy of the array
    $prev = prev($copy);
    echo "prev: $prev\n";

    next($arr);     // don't forget to advance the pointer on the original array
}

I've demonstrated the prev bit just for the example. You can easily do that without prev() by saving the element at the end of each iteration.

The if empty bit resets the array pointer to the beginning, because foreach will advance the pointer once when it makes a copy of the array.

The above example yields:

node: 1
next: 2
prev: 

node: 2
next: 3
prev: 1

node: 3
next: 4
prev: 2

node: 4
next: 5
prev: 3

node: 5
next: 
prev: 4

If you have to do something like this though, there might be a better way just by rearranging your data structure (hard to tell without code).

Upvotes: 1

Matt Lowden
Matt Lowden

Reputation: 2616

Although I've had choppy results with them in the past you can use the below functions to move the current array pointer.

Hopefully that'll help.

Upvotes: 4

chiborg
chiborg

Reputation: 28104

IHMO it's not possible with a simple foreach loop on an array that has non-numeric indexes. But you can extend the SPL class CachingIterator to wrap your array in this. In your extended class you can implement methods to return the previous and next index/value without advancing the internal element pointer.

If you have an array with numeric indexes use a for loop instead of a foreach. You can then use $i+1 and $i-1 to look at different array indexes than the current index.

Upvotes: 0

Mat
Mat

Reputation: 2428

I assume you are using php. I dont think it's possible, you must know the index of element and index the array. Sth like this:

$i=0;
foreach ($array as $element){
    echo $element;
    //do sth with $array[$i+1];
    //do sth with $array[$i-1];
    $i++;
}

Have no other clue

Upvotes: -3

Related Questions