This question already has answers here:
The 3 different equals
(5 answers)
Closed 6 years ago.
I am puzzled by an issue in my code and hoping someone else can help me shed some light on why my loop is omitting the first element (array[0]) of the array.
the Code
foreach ($a as $key => $val) {
for ($i=0; $i<count($val); $i++) {
$x = $i; //this helps me jump logical arguments without the use of else
// First Test
if (isset($val[$i+2]) && $x = $i) {
//Do a bunch of stuff
if (isset(the stuff done above)) {
// do other things and reset $i to jump through the array
$i=$i+2;
}
else {
unset($things);
unset($otherthings);
}
}
}
// Second Test
if (isset($val[$i+1]) && $x = $i) {
//Do a bunch of stuff
if (isset(the stuff done above)) {
// do other things and reset $i to jump through the array
$i=$i+1;
}
else {
unset($things);
unset($otherthings);
}
}
}
// Third and final test
if ($x = $i) {
//do other things
}
}
}
the Problem
I can't seem to understand why but the for loop or the IF statements (I am not 100% sure which one) fail to run through the first element of the array[0].
It runs fine from array[1] onward but even though i have tested that $x is indeed = to $i and therefore test 3 at the very least should work, the loop seems to run one loop past all the IF's and then start working from array[1].
What I have tried
I have changed for ($i=1; $i<$val; $i++) and this works fine (e.g. does not omit anything) from the start (but of course does not solve my problem as I am still missing array[0])
I have tested in the code if echo $val[0] prints out at the beginning of the code and it does
I have also tested $x = $i and these also work
It is one of those issues that feel too silly to change everything in my code but having searched a lot throughout stack overflow and google for similar issues, I cannot seem to find out why.
There must be something wrong I cannot see in the way I have written the loop?
Use $x == $i to test for equality, not $x = $i, which is an assignment.
Related
Hey guys i've the following scenario
$col = new ArrayObject();
for ($i = 0; $i < 5; $i++)
{
$objItem = new stdClass;
$objItem->someVar = $i;
$col->append($objItem);
}
Now i want to remove some key via offsetUnset and did the following
foreach($col AS $key => $objItem)
{
if ($key == 2)
{
$col->offsetUnset($key);
}
echo $key.'\n';
}
The funpart now is the unexpected output
0
1
2
4
For a better illustration - if you put a continue in like
foreach($col AS $key => $objItem)
{
if ($key == 2)
{
$col->offsetUnset($key);
continue;
}
echo $key.'\n';
}
the output is
0
1
4
I never ever would've thought it bypasses the key number 3 in this ArrayObject just because i removed the previous item - it looks like the internal pointer was incremented twice or something like that...
Keep in mind i also tried something like
$it = $col->getIterator();
foreach($it AS $key => $objItem)
{
if ($key == 2)
{
$col->offsetUnset($key);
}
echo $key."\n";
}
the output is the same
Question:
Is this a normal behavior or do i overlook something crucial here?
pS: As nigel Ren pointed out this as a possible duplicate of Php, Spl, ArrayIterator, i've to point out i was looking here for an ArrayObject solution and didn't found any (i now know the ArrayIterator problem is probably the same) - but i would've never guessed that those are related to each other - in this respect i plead for not closing this question because it might help others too
The solution for this Bug is actually pretty simple and was posted here
by a user called Tsounabe.
I'm putting here his solution - only with one change - he was referring to an ArrayIterator and i was talking about an ArrayObject - but both are using the same function getArrayCopy
foreach($col->getArrayCopy() AS $key => $objItem)
{
if ($key == 2)
{
$col->offsetUnset($key);
continue;
}
echo $key.'\n';
}
Conclusion
The only satisfying solution here in order to avoid this bug is the use of getArrayCopy() which is documented on the official PHP Site under https://secure.php.net/manual/de/arrayobject.getarraycopy.php
In your code it is resetting object key after $col->offsetUnset($key); and continue with next key 3 after resetting it would the element whose ->someVar value is 4, that's why you get this output.
So you can simply use another iteration to print your object. it would work.
Live demo
Out put
0
1
3
4
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Is it possible to do something like this:
if ($boolean == true) {
foreach ($variables as $variable) {
}
// some code that can be run either with a loop or without
if ($boolean == true) {
} // end the foreach loop
}
Or is there another way to do this without rewriting the same code twice just to satisfy all possibilities?
The conventional way is to always use a loop. If there is only one item, then you can still loop just once.
Contrived example
$values = …;
if (!is_array($values)) {
$values = array($values);
}
foreach ($values as $value) {
// Do your work
}
I'm not sure if I understand exactly what you're asking, but if you want to run a loop at least once, and continue looping for a condition then "Do While" is your answer. A do while works just like a while, but checks AFTER the first loop is run - meaning it always runs at least once.
PHP Docs for Do While
Do-while loops are very similar to while loops, except the truth expression is checked at the end of each iteration instead of in the beginning.
Example:
$arrayofstuff = array('one ','two ','three '); // Optional array of stuff
$i=0; // Counts the loops
echo 'starting...';
do {
// Do stuff at least once here
// Array stuff if needed
if(isset($arrayofstuff[$i])) {
echo $arrayofstuff[$i]; // Uses loop # to get from array
} else {
break; // ends loop because array is empty
}
$i++;
} while (true);
For what it's worth, forcing a variable into a single value array would probably be easier to read. As you can see there's a lot going on here for such a simple task.
(Dionne Warwick voice) That's what functions are for:
function doSomething() {
//whatever
};
if ($boolean)
for($variables as $variable) doSomething();
else
doSomething();
That kind of syntax you thought about isn't valid in PHP. It's a very clever idea though. But code maintenance of one of there would bring hell on earth. Better forget it.
why not just plain:
if($boolean){
foreach($a as $b){
// do stuff
}
}else{
// do other stuff
}
What you want would be done like so...
foreach ($variables as $variable) {
// some code that can be run either with a loop or without
if ($boolean !== true) {
break;
}
}
But this is not as readable as just using an if/else statement
For ex. If I have a function rand(0,2). How do i build a function such that
resc(100,rand(0,2));
Prints the value of rand(0,2) 100 times? For that matter. Any function that is printable.
I tried this.But doesnt seem to work.
<?php
function resc($i, $f) {
if ($i != 0) {
print $f;
return resc($i-1, $f);
} else {
print $f;
}
}
resc(4, rand(0, 1));
?>
If you just want to print a bunch of random ints:
function resc_int($recursions, callable $func, $args = array()) {
for($i = 0; $i < $recursions; $i++) {
echo call_user_func_array($func, $args);
}
}
// resc_int(100, "rand", array(0, 1));
Completely untested. Caveat Lector.
The way this works is that instead of using recursion (which will use more and more memory the more recursions you have, as you can't garbage collect something with active references or you will get a segmentation fault later in PHP if it tries to access it), it uses iteration.
There's two kinds of "looping" in a sense.
Looping/Recursion.
Technically Recursion is a loop, as you continue recursing until you reach a stop condition (else you get an infinite loop, which is bad for fairly painful reasons). The loop construct in PHP is while().
Iteration
In pretty much every single case (unless you have a really good reason) this is always the better choice when you need something that loops. Iteration is, to put it simply, counting up or down to a target integer. This is the for() construct; and hence, also the foreach() construct, which uses the number of elements in an array as a target integer and then counts towards it, picking elements out of the array as it goes.
This is more memory efficient, and is remarkably easy to work with in PHP. It can also infinite loop, like while can (just give it an impossible condition to work towards), so watch out for that.
In short: have fun with the standard library (pretty much every function you regularly need is somewhere in there), and remember that recursion is your last option, not the first.
function resc($times, $cbFtn, Array $cbFtnArgs = array()) {
if ($times != 0) {
print call_user_func_array($cbFtn, $cbFtnArgs);
resc($times - 1, $cbFtn, $cbFtnArgs);
}
}
resc(4, 'rand', array(0, 1));
I'm trying to teach myself PHP. My current exercise combines a form (not included in the code, but it works) that requires the user to enter the name of a city. The loop and the if statement compare the entry with an array of state capitals to return an answer that states whether that city is a state capital or not.
If I leave out the elseif part, the code runs ok, but I have no alternative when the user has entered a city that is not in the array. But with the elseif, the first part of the loop doesn't execute. For example, if I enter "Albany" without the elseif, I get "Albany is the capital of New York." But if I enter it with the elseif statement, it runs the loop until it finds "New York" and it prints "Albany is the capital of New York."
I've googled this, and I've read the books on PHP that I have. And I also know that I'm making a very basic mistake. Any guidance would be greatly appreciated.
for ($i = 0 ; $i < count($stateCapitalNames); $i++)
if ($enteredCity == $stateCapitalNames[$i]) {
print "<p>$enteredCity is the capital of <b>$stateNames[$i]</b>. </p>";
} elseif ($enteredCity != $stateCapitalNames[$i]){
print "<p>$enteredCity is not the capital of a state.</p>";
}
?>
You can use break to leave the for loop.
You should look at array_search to find the index you are looking for. array_search returns false if the capital does not exist.
For instance
$i = array_search($enteredCity, $stateCapitalNames);
if($i !== false)
{
echo "<p>$enteredCity is the capital of <b>",$stateNames[$i],"</b>. </p>";
}
You are missing your brackets in your for loop. I'm surprised the elseif is the culprit and that the code doesn't fail anyways. But here is what I would do, errors aside:
$correct = false;
for ($i = 0 ; $i < count($stateCapitalNames); $i++){
if ($enteredCity == $stateCapitalNames[$i]) {
$correct = true;
$stateNames = $stateNames[$i]; // Updated $stateNames variable
break;
}
}
//You can check $correct here...
if($correct){
print "<p>$enteredCity is the capital of <b>$stateNames[$i]</b>. </p>"; /*Removed [$i] from $stateNames. For some reason, $stateNames[$i] wasn't updating outside the loop, but now it is.
}
This way, no matter what, until the code finds a correct answer, the user is wronge. Once it finds the right answer, it sets it as correct and exits the loop by setting $i to the length of the array.
`I have a function called lets say calculate; what i want to do is run some loops with in the function calculating an outcome. at times this function does fail as it will get stuck in a loop, so iv got it covered to exit the loop but my problem is i want to restart this function and hope it come out with an outcome if not i will try again... on average the request does not have an outcome around 1 in 20, i need to restart the function from a clean slate.
i have tried to unset all the vars before i rerun the process with out success.please note this function will fail at times from the information handed to the process, un avoidable so
when this accurs i just want to rerun the function automatically to generate an outcome.
http://www.gamezslave.com/test/DynamicSlots.swf this is my test prototype give you an idea
sometimes you refresh it will error because of this factor.
<?php
$checker = 0; // if i cant get a result i could use this will tick up until condition
function shuffleArray($myArray) {
$value_count = array_count_values($myArray);
$last_value = $myArray[count($myArray) - 1];
unset($myArray[count($myArray) - 1]);
$shuffle = array();
$last = false;
while (count($myArray) > 0) {
$keys = array_keys($myArray);
$i = round(rand(0, count($keys) - 1));
while ($last === $myArray[$keys[$i]] ) {
$i = round(rand(0, count($keys) - 1));
echo "stuck";
$checker++;
if($checker>10){
echo " Too many checks so die, and restart process ";
return false;
bob; // this is the check function to goto and restart
}
}
$shuffle[] = $myArray[$keys[$i]];
$last = $myArray[$keys[$i]];
unset($myArray[$keys[$i]]);
}
if ($last_value === $last) {
$i = 0;
foreach($shuffle as $key=>$value) {
if ($value !== $last_value) {
$i = $key;
break;
}
}
array_slice($shuffle, $i + 1, 0, $last_value);
} else {
$shuffle[] = $last_value;
}
return $shuffle;
}
print_r(shuffleArray(array(1,5,5,3,7,7,7,7))); // just a example
function bob(){
if($checker>10){
$checker = 0;
shuffleArray();
echo "bob";
reset($myArray); // thought this may clean/reset the array i couldnt use
}
}
The idea this shuffle returns that no two symbols elemts of the same will be next to each other but sometimes at the end of the array as its shuffling randomly im left with bad odds (apple, orange, orange, orange) so what i need to do is resart this process again from start take in mind there is about 10 different item in the array and duplicates of each for example 10 apples ,10 oranges 4 bannanas 3 grapes sometimes the shuffle manages to generate an outcome where im stuck with too many of the same item at the end of the array wich then i need to rerun the script(and this bit is the problem) i dont know how.
Are you using globals?
If yes: Stop that. It's terrible practice. Seriously. There's never a reason to use globals with any sort of sane code.
If no: There's nothing to do. Each function invocation is a clean slate.
EDIT After seeing the code, I'm kinda speechless.
http://us3.php.net/manual/en/function.shuffle.php
I would set defaults to all variables inside of your function, and pass anything active as a parameter. Then use a set of return codes to indicate success or failure, or validate the outcome in some way and re-run.
I'm agreeing with Tyler Eaves here and i wanted to add as another reply a very important topic in programming:
A function "should" in theory be as scalar as possible meaning that it should not affect the outside world and should return the same information everytime for the same parameters.
If you call a function with parameter X, Y and Z and call it again while your system is in the same state, the function should return the exact same result.
But if a function is not scalar (Virtual for instance), such as dependant on external data (files, database rows or single instance accessible class data) then you should theorically not affect that external data from this function or else calling the function multiple times yield different results...