Jump to content

[SOLVED] for() construct with letters


neylitalo

Recommended Posts

I observed this behavior when running a for() loop on letters, like this:

 

<?php
for($a = "A"; $a <= "Z" ; $a++)
{
    echo $a;
}
?>

 

After it runs through the entire alphabet (A-Z), then it starts in on pairs of letters. AA, AB, AC, all the way to AZ. And once it's done with A, it goes on to BA, BB, BC, and so on, to BZ. Then it loops through all of the other letters similarly. The "quirk" (if the whole thing isn't one big quirk) is at the end: It stops at YZ. It doesn't go on to ZA.

 

I tested this:

 

<?php
for($a = "A"; $a <= "Y"; $a++)
{
    echo $a;
}
?>

 

It runs through the alphabet, but only up to Y, and stops there, no pairs of letters.

 

I suspect this may be a "bug" in PHP itself, but does anybody have a logical explanation for this behavior?

Link to comment
Share on other sites

LOL, I wrote some code just like that a while ago.

 

Here is what I think is happening.

 

This is similar to when you sort the strings "10" and "2". "10" will come before "2", because the sort (comparison) is operating character by character, left to right.

 

The comparison operator <= is not comparing the strings, it is comparing the values on both sides as an array of characters.

 

For values A..Z, $a only contains one element $a[0], but because the comparison uses the "=" condition too, it means that $a will be incremented to AA on the next comparison.

 

Once $a increments from Z to AA, $a now has two elements $a[0] and $a[1]. The "Z" is probably promoted to a two element string "Znull" for the comparison as well. As long as $a[0] is <= "Z" the comparison is still true. That gets you from AA to YZ.

 

When this increments to ZA, $a[0] is now equal to "Z" (or the first array element of "Znull") and the comparison then checks the $a[1] element to see if the less-then "<" part of the comparison is true or false. Since the $a[1] element is no longer less-than or equal "<=" to the second element of "Z" or "Znull", the comparison is finally false.

 

I recommend making an array of the characters A to Z using a range() function and then using a foreach() loop to iterate over that array of characters.

 

Edit: In case you tried $a < "AA". It won't work for the same reason. When $a[0] becomes "B", that is greater than the first element of "AA" and the comparison is false.

Link to comment
Share on other sites

For the code to use a for() loop and work, it would need to be as follows (tested) -

 

for($a = "A"; strcmp(str_pad($a, 2, " ",STR_PAD_LEFT),"AA") < 0 ; $a++)

 

An array of letters and a foreach() loop is starting to look pretty good and would have much faster speed too.

Link to comment
Share on other sites

The following doesn't solve the OP's original query, but gives the results that were mentioned:

<?php
        $az = range('A','Z');
        for ($i = 0;$i<count($az);$i++)
            for ($j=0;$j<count($az);$j++)
                echo $az[$i] . $az[$j] . "\n";
?>

 

Ken

Link to comment
Share on other sites

For values A..Z, $a only contains one element $a[0], but because the comparison uses the "=" condition too, it means that $a will be incremented to AA on the next comparison.

 

This doesn't make sense to me. Why should the = make it increment to AA, and not stop at Z? After all, I didn't tell it "<= 'ZZ'", I said "<= 'Z'". By all logic, it should stop at Z, not go on to AA. And if we sidestep that point of logic, why does it stop at YZ? Why not go to ZA?

Link to comment
Share on other sites

For() loops execute the third parameter at the end of the loop. So, when $a is a "Z", $a <= "Z" is true, the code in the loop executes, then $a++ makes $a into an "AA" and that is what is used in the next comparison. Since the leading character in $a is still less than "Z", the comparison is true and the loop continues.

 

As to why it stops at "YZ", read what I wrote a couple of more times. The leading character in $a (for "AA" to "YZ") is less than "Z" until $a is "ZA". It is only then that the comparison looks at the second character in $a and finds that the "A" in "ZA" is no longer <= to the second character in "Z" because "Z" does not contain a second character.

Link to comment
Share on other sites

As to why it stops at "YZ", read what I wrote a couple of more times. The leading character in $a (for "AA" to "YZ") is less than "Z" until $a is "ZA". It is only then that the comparison looks at the second character in $a and finds that the "A" in "ZA" is no longer <= to the second character in "Z" because "Z" does not contain a second character.

 

That's exactly what I was looking for, and the whole thing even makes sense, in a twisted sort of way. Thanks.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • 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.