Jump to content

[SOLVED] Reset a foreach loop


TankedShark

Recommended Posts

Is there any way to reset a foreach loop, or do I have to use a for loop instead?

 

I'm trying to get this to print "1 5 10 1 5 10 "

 

<?php
$arrA = array(1, 5, 10);
$firstRun = true;
foreach ($arrA as $value) {
    echo $value.' ';
    if ( ($firstRun == true) && ($value == 10) ) {
        $firstRun = false;
        reset($arrA);
    }
}
?>

Link to comment
https://forums.phpfreaks.com/topic/135452-solved-reset-a-foreach-loop/
Share on other sites

I do not think it is possible, but you could make your own function that is recursive...

 

<?php
$arrA = array(1, 5, 10);
$firstRun = true;
foreachTwice($arrA, true);

function foreachTwice($array, $continue) {
foreach ($array as $value) {
	echo $value.' ';
	if ( ($continue) && ($value == 10) ) {
		foreachTwice($array, false);
	}
}
}

?>

 

That can also be manipulated to go so much further to, as it is it will only run twice.

This is already going to be used in the context of a recursive function. It's not the output that I'm looking for, it's the sequence. Maybe this will better illustrate it:

 

Desired output is "1 5 1 5 10 "

 

<?php
$arrA = array(1, 5, 10);
$firstRun = true;
foreach ($arrA as $value) {
    echo $value.' ';
    if ( ($firstRun == true) && ($value == 5) ) {
        $firstRun = false;
        reset($arrA);
    }
}
?>

edit: removed below and re-thinking it.

 

<?php
$arrA = array(1, 5, 10);
$firstRun = true;
foreachLoop($arrA, 5); 

function foreachLoop($array, $endAt=false) {
foreach ($array as $value) {
	echo $value.' ';
	if (!$endAt)
		continue; // if endat is false just continue and skip below

	if (($value == $endAt) ) {
		foreachLoop($array, false);
		break;
	}
}
}
?>

 

That would work, that way you give it a value and once it hits that it breaks out etc.

 

As for which is better, this or a for loop really it is your call. But foreach doesn't have a built in function to do that as far as I know.

edit: removed below and re-thinking it.

 

code

 

That would work, that way you give it a value and once it hits that it breaks out etc.

 

As for which is better, this or a for loop really it is your call. But foreach doesn't have a built in function to do that as far as I know.

 

I guess my example isn't a good enough parallel to my situation, as I have no idea how to implement your solution. What I'm ultimately trying to do is to flatten a multi-dimensional array, with elements of Glue inserted between the elements of a childless sub-array, and elements of Break inserted between the elements of a parent array. Since my current function iterates through the array passed to it only once, it will insert A between non-array elements even if an array element is present further down the line. If I run it on $arrA, defined as array(1, 2, array(3, 4), 5), I want the result equal array(1, B, 2, B, 3, G, 4, B, 5). In its present form, the result equals array(1, G, 2, G, 3, G, 4, B, 5), because it assumes that the top-level array is childless until it finds otherwise. Here's the code, with the faulty reset:

 

<?php
/////////////
// brackets are incorrect right now
/////////////
function flat_insert($source, $glue, $break) {
    if (!is_array($source)) {
        return null;
    }
    $stack1 = array(); //this will be returned
    $child = true;
    foreach ($source as $value) {
        if ((is_array($value)) && ($child == true)) { //if we find an array
            $child = false;
            reset($source); //re-start loop
            $stack1 = array(); //clear stack for restart
        }
        else if ((is_array($value)) && ($child == false)) { //if we already know we're in a parent, and we find a sub-array
            foreach (flat_insert($value, $glue, $break) as $v2) { //iterate through recursed sub-array
                $stack1[] = $v2;
            }
            unset($v2);
            if ($value != end($source)) { //only insert fill if we're not at the end
                $stack1[] = $break;
            }
        }
        else if ($child == false) { //parent array, current is not a sub-array
            $stack1[] = $value;
            if ($value != end($source)) {
                $stack1[] = $break;
            }
        else { //presume childless
            $stack1[] = $value;
            if ($value != end($source)) {
                $stack1[] = $glue;
            }
        }
    }
    unset($value);
    return $stack;
}
?>

Alright, I got it. The trick is to pass a new variable by reference into all extra elements, then change the value of the variable at the end of the function based on whether it's a parent or child. Here's the function and some sample outputs:

 

<?php
function flat_insert2($source, $glue, $break) {
    if (!is_array($source)) {
        return null;
    }
    $stack1 = array();
    $child = true;
    $insert = $glue;
    foreach ($source as $value) {
        if (is_array($value)) { //if we find a sub-array in current element
            $child = false;
            foreach (flat_insert2($value, $glue, $break) as $v2) { //iterate through recursed sub-array
                $stack1[] = $v2;
            }
            unset($v2);
        }
        else { //current element is not an array
            $stack1[] = $value;
        }
        $stack1[] = &$insert; //pass insert as reference
    }
    unset($value);
    array_pop($stack1); //remove trailing insert
    if ($child == false) {
        $insert = $break;
    }
    return $stack1;
}
?>

 

<?php
$arrF = array(8, 9);
$arrE = array(6, 7);
$arrD = array(4, 5);
$arrC = array($arrD, $arrE, $arrF, 10);
$arrB = array(2, 3, $arrC);
$arrA = array(1, $arrB, 11);
echo 'Array A: '.implode(flat_insert2($arrA, '-', ' ')).'<br />';
echo 'Array B: '.implode(flat_insert2($arrB, '-', ' ')).'<br />';
echo 'Array C: '.implode(flat_insert2($arrC, '-', ' ')).'<br />';
echo 'Array D: '.implode(flat_insert2($arrD, '-', ' ')).'<br />';
?>

Output:
Array A: 1 2 3 4-5 6-7 8-9 10 11
Array B: 2 3 4-5 6-7 8-9 10
Array C: 4-5 6-7 8-9 10
Array D: 4-5

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.