.. index::  while; index for sequence
   sequence with while
   

.. _While-Sequence:


While-Statements with Sequences
================================= 

One Character Per Line
-----------------------

We will process many sequences or collections.  At this point
the only collection we have discussed is a string - a sequence of
characters that we can index.

.. _OneCharPerLine:

.. index::  example; OneCharPerLine
   OneCharPerLine example
   
Consider the following silly function description and heading as a start:

.. literalinclude:: ../source/examples/char_loop1/char_loop1.cs
   :start-after: chunk
   :end-before: {
 
``OneCharPerLine("bug")`` would print:

..  code-block:: none

       b
       u
       g

We are accessing one character at a time.  We can do that with
the indexing notation.  Thinking concretely about the example above,
we are looking to print, ``s[0]``, ``s[1]``, ``s[2]``.  If
we knew we would always have three characters, we could do this
with three explicit print statements, but we are looking to write a general
definition for an arbitrary length string:
This requires a loop.  
For now our only option is a ``while`` loop.  We can follow our basic 
:ref:`loop planning rubric <loop-rubric>`, 
one step at a time:
The index is changing in a simple repetitive sequence.  
We can call the
index ``i``.  Its initial value is clearly 0. 
That is our initialization.  We need a ``while`` loop continuation 
condition.
For the 3-character string example, the last index above is 2.
In general we want *all* the characters.  Recall the index of the last 
character is the length - 1, or with our parameter ``s``, ``s.Length - 1``
The ``while`` loop condition needs to allow indices through 
``s.Length - 1``.  We could write a condition with ``<=`` or more
concisely::

    while (i < s.Length) {

In the body of the loop, the main thing is to print the next character,
and the next character is ``s[i]``::

    Console.WriteLine(s[i]);


.. index:: 
   single: ++ increment
   single: -- decrement
   operator; ++ increment
   operator; -- decrement
       
We also need to remember the part to get ready for the next time 
through the loop.  We have dealt with regular sequence of values
before.  We change ``i`` with::

    i = i+1;
    
This change is so common, there is a simpler syntax::

    i++;
    
This increases the value of the numeric variable i by 1.
(The reverse is ``i--;``) [#plusplustype]_

So all together:

.. literalinclude:: ../source/examples/char_loop1/char_loop1.cs
   :start-after: chunk
   :end-before: chunk
 
You can test this with example :repsrc:`char_loop1/char_loop1.cs`.

This is a very common pattern.  
We could do anything we want with each individual character, 
not just print it.

.. index:: ReversedPrint example
   
.. _reversed-print-example:
   
String Backwards Exercise/Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
	
Here is a variation:

.. literalinclude:: ../source/examples/reversed_print/reversed_print.cs
   :start-after: chunk
   :end-before: {

There are a few changes:

- You do not want to go on to the next line, so use ``Write``, 
  not ``WriteLine``.
- It is still a regular sequence of character indices, but
  we are working backwards through the string.  We have created
  a decreasing sequence before.  Where do
  you start?  Where do you stop?  What is the condition? How do you
  get ready for the next time through the loop? (Remember our newest
  notation.)
  
Our code with driver is in
:repsrc:`reversed_print/reversed_print.cs`.

.. index:: string; PrintVowels
   PrintVowels example
   
.. _PrintVowels:
   
Print Vowels Function
------------------------

Let us get more complicated.  Consider the function described:

.. literalinclude:: ../source/examples/vowels/vowels.cs
   :start-after: chunk
   :end-before: {

For instance PrintVowels("computer") would print:

..  code-block:: none

     o
     u
     e

We have seen that we can go through the whole string and do the same
thing each time through the loop, using ``s[i]`` in some specific way.

This new description seems problematic.  We do *not* appear to want to do
the same thing each time:  We only want to print *some* of the 
characters.  Again your eyes and mind are so fast, you likely miss what you
need to do when you go through ``PrintVowels`` by hand.  Your
eyes let you just grab the vowels easily, but think, what is actually
happening?  You are checking each character to see **if** it is a vowel,
and printing it if it is:  You are doing the same thing each time -
*testing* **if** the character is a vowel.  The pseudocode is   ::

    if (s[i] is a vowel) {
       print s[i]
    }

We *do* want to do this each time through the loop.  We *can* use 
a ``while`` statement.

Next task:  convert the pseudocode "s[i] is a vowel" to C#.

There are multiple approaches.  The one you get by following your
nose is just to consider all the cases where it is true::

   s[i] == 'a'
   s[i] == 'e'
   s[i] == 'i'
   s[i] == 'o'
   s[i] == 'u'

How do you combine them into a condition?  
The letter can be a *or* e *or* i *or* o *or* u.  We get the code:

.. literalinclude:: ../source/examples/vowels/vowels.cs
   :start-after: chunk
   :end-before: chunk

That has a long condition!  Here is a nice trick to shorten that:
We want to check if a character is in a group of letters.  We have
already seen the string method IndexOf.  Recall we can use it to see if
a character is in or not in a string.  We can use ``"aeiou".IndexOf(s[i])``.
We do not care *where* ``s[i]`` comes in the string of vowels.  
All we care is that ``"aeiou".IndexOf(s[i]) >= 0``.

.. index:: string; Contains
   Contains for strings
   
This is still a bit of a mouthful.  Often it is just important if a
character or string is *contained* in another string, not where it appears,
so it is easier to
use the string method ``Contains``.  Though IndexOf takes either a string
or a character as parameter, ``Contains`` only takes a string.  There is a 
nice quick idiom to convert anything to a string:  use ``""+``. 
The condition could be ``"aeiou".Contains(""+s[i])``.  
The ``"" + s[i]`` adds
the string version of ``s[i]`` to the empty string.

The function is still not as general as it might be:
Only lowercase vowels are listed.  We could do something with
``ToLower``, or just use the condition: ``"aeiouAEIOU".Contains(""+s[i])``

This variation is in example :repsrc:`vowels2/vowels2.cs`.

.. literalinclude:: ../source/examples/vowels2/vowels2.cs
   :start-after: chunk
   :end-before: chunk


.. index:: example; check_digits
   IsDigits example function
   
.. _IsDigits:

IsDigits Function
---------------------

Consider a variation, determining if *all* the characters
in a string are vowels.  We could work on that, but it is 
not very useful.  Instead let us consider if all the 
characters are digits.  This is a true-false question, so the function
to determine this would return a Boolean result:

There are several ways to check if a character is a digit.  We could use the
``Contains`` idiom from above, but here is another option:
The integer codes for digits are sequential,
and since characters are technically a kind of integer, we can 
compare:  The character ``s[i]`` is a digit if it is in the range from ``'0'``
to ``'9'``, so the condition can be written::

    '0' <= s[i] && s[i] <= '9'
    
Similarly  the condition ``s[i]`` is not a digit, can be written 
negating the compound condition as in :ref:`Compound-Boolean-Expressions`::

    s[i] < '0' || s[i] > '9'
    
If you think of going through by hand and checking, 
you would check through the 
characters sequentially and if you find a non-digit,
you would want to *remember* that the string is not only digits.

One way to do this is have a variable holding an answer so far::

     bool allDigitsSoFar = true;
     
Of course initially, you have not found any non-digits, so it starts off true.  
As you go through
the string, you want to make sure that answer is changed to ``false`` 
if a non-digit is encountered::

     if ('0' > s[i] || s[i] > '9') {
         allDigitsSoFar = false;
     }

When we get all the way through the string, the answer so far is the
final answer to be returned::

   /// Return true if s contains one or more digits
   /// and nothing else. Otherwise return false. 
   static bool IsDigits(string s)
   {
      bool allDigitsSoFar = true;
      int i = 0;
      while (i < s.Length) {
         if (s[i] < '0' || s[i] > '9') {
            allDigitsSoFar = false;
         }
         i++;
      }
      return allDigitsSoFar;
   }

Remember something to always consider:  edge cases.
In the description it says it is true for a string of *one or more* digits.

Check examples of length 1 and 0.  
Length 1 is fine, but it fails for the empty string,
since the loop is skipped and the initial answer, ``true`` is returned.

There are many ways to fix this.  We will know right up front that the answer
is false if the length is 0, and we could immediately set
``allDigitsSoFar`` to false.  We would need to change the initialization 
so it checks the length and chooses the right value for ``allDigitsSoFar``,
true or false. Since we are selecting between two values,
an ``if`` statement should occur to you::

  bool allDigitsSoFar;
  if (s.Length > 0) {
      allDigitsSoFar = true;
  }
  else {
      allDigitsSoFar = false;
  }
      
If we substitute this initialization for ``allDigitsSoFar``, 
the code will satisfy the edge case, and the code will always 
work.  Still, this code can be improved: 

Examine the ``if`` statement more closely:

    | if the condition is  ``true``, ``allDigitsSoFar`` is ``true``; 
    | if the condition is ``false``, ``allDigitsSoFar`` is ``false``; 

See the symmetry: the value assigned to ``allDigitsSoFar`` is always
the *value of the condition*.

A *much* more concise and still equivalent initialization is just::

    bool allDigitsSoFar = (s.Length > 0); 
    
In more generality this 
conciseness comes from the fact that it is a *Boolean* value that
you are trying to set each time, based on a *Boolean* condition:  You do not
need to do that with an ``if`` statement!  You just need an 
assignment statement.  If you use an ``if`` statement in such a situation,
you being verbose and marking yourself as a novice!

It could even be slightly more concise:  The precedence of assignment is
very low, lower than the comparison ``>``, 
so the parentheses could be omitted.  We think the
code is easier to read with the parentheses left in, as written above.

The whole function would be:

.. literalinclude:: ../source/examples/check_digits1/check_digits1.cs
   :start-after: chunk
   :end-before: chunk

You can try this code in example :repsrc:`check_digits1/check_digits1.cs`.

.. index::  return; from inside loop

Note that we earlier made an improvement by replacing an |if-else| statement 
generating a Boolean value by a simple Boolean assignment.  
In the most recent sample code, there is an ``if`` statement setting a Boolean
value::

            if (s[i] < '0' || s[i] > '9') {
               allDigitsSoFar = false;
            }
            
You might be tempted to replace this ``if`` statement by a simple Boolean
assignment::

    allDigitsSoFar = (s[i] < '0' || s[i] > '9');  // bad!
    
Play computer with this change to see for yourself why it is bad, before
looking at our explanation below....

The place where we originally said to use a simple Boolean assignment was
replacing an |if-else| statement, that *always* set a Boolean value.  In the more
recent correct code for digits, we had a simple ``if`` statement, 
and were only setting the boolean variable
to ``false`` *some* of the time: when we had *not* found a digit.  The bad code
sets the variable for *each* character in the string, 
so it can change an earlier ``false`` value back to ``true`` for a later digit.
The final value
always comes from the the *last* character in the string!  We want the
function to come up with an answer ``false`` if *any* character is not a digit,
not just the last character.  The bad code would give the wrong answer
with the string "R2D2".  If you do not see that, play computer with this string
and the bad code variation 
that sets ``allDigitsSoFar`` every time through the loop.  

There is a less commonly useful way to make an assignment without ``if`` 
work here [#boolassign]_, but a much more important, 
improved approach follows:
   
The last correct code is still inefficient.  If an early
character in a long string is not a digit, we already know the 
final answer, but this code goes through and still checks all the
other characters in the string!  People checking by hand 
would stop as soon as they found a
non-digit.  We can do that in several ways with C#, too.  
Since this is a function, and we would know the final answer
where we find a non-digit, 
the simplest thing is to use the fact that a return statement
*immediately terminates* the function (even if in a loop).

Instead of setting a variable to ``false`` to *later* be returned,
we can return right away, using the loop::

      while (i < s.Length) {
         if (s[i] < '0' || s[i] > '9') {
            return false;
         }
         i++;
      }

What if the loop terminates normally (no return from inside)?  
That means no
non-digit was found, so if there are any characters at all,
they are all digits. There are 
*one or more* digits as long as the string length is *positive*.
Again we do *not* need an |if-else| statement to check the length and
set the Boolean result.  
Look in the full
code for the function:

.. literalinclude:: ../source/examples/check_digits2/check_digits2.cs
   :start-after: chunk
   :end-before: chunk

The full code with a ``Main`` testing program is in 
example :repsrc:`check_digits2/check_digits2.cs`.

Returning out of a loop 
is a good pattern to remember when you are searching for something, 
and you know the final answer for your function as soon as you find it.

.. index:: playing computer; loop
   loop; playing computer
   
Play Computer With a Loop
------------------------------

We have not given you a chance to play computer with a loop.  Here is
some simple silly code,
:repsrc:`loop_steps/loop_steps.cs`,
also using a sequence: 
 
.. literalinclude:: ../source/examples/loop_steps/loop_steps.cs
   :linenos:

Play computer, completing the table.  You fill in the line numbers,
carefully.  The sequence is *not* 9, 10, 11, 12, 13!

====  ==  =======================================
Line  i   Comment
====  ==  =======================================
5     \-  Start at beginning of Main
7         set s = "abcd" (does not change)
8     1   initialize i
...
====  ==  =======================================

.. [#plusplustype]

   To be complete, the statements ``c = c + 1;`` and ``c++;`` are not always 
   equivalent.
   
   .. fails in tex
       To be complete, these two statements are not always 
       totally equivalent::
          
          c = c + 1;
          c++;
      
   In ``c++`` the type of ``c`` must be numeric, but not necessarily ``int``.  
   It could be a *smaller* type, like ``char``.    
   
   .. fails in tex 
       For instance ::
       
           char c = 'A';
           while (c <= 'Z') {
               Console.Write(c);
               c++;
           }
       
       prints the whole English alphabet, capitalized.  
    
   With a  ``c`` of type ``char`` the ``c++`` could
   not be replaced by ``c = c + 1``, but you could use ``c = (char)(c + 1)``:
   The ``int`` literal 1 forces
   the sum expression to be an ``int``, which must be cast back to a ``char`` to be
   assigned to ``c``.  Similarly with the ``--`` operator.



.. [#boolassign]

   The Boolean assignment did not work when ``allDigitsSoFar`` was already
   ``false``, and the next character was a digit.  This could be fixed with
   a compound Boolean expression in the assignment:
   
   ``allDigitsSoFar = allDigitsSoFar  && (s[i] < '0' || s[i] > '9');``
   
   This way, once ``allDigitsSoFar`` is ``false``, it stays ``false``.


Duplicate Character Exercise
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Create a file ``double_char_test.cs``, 
and write and test a function with the documentation and heading below::

   /// If two consecutive characters in s are the same, return true.
   /// Return false otherwise.  Examples: 
   /// HasDoubleChar("bigfoot") and HasDoubleChar("aaah!") are true; 
   /// HasDoubleChar("treated") and HasDoubleChar("haha!") are false.
   static bool HasDoubleChar(string s)
   
You may want to play computer on a short example - there is an easy mistake
to make.  
   