``for`` Statement Examples ================================== Format Output: Console.Write() ------------------------------- Thus far all of our ``for`` loops have used a sequence of successive integers. You can do a quick test in ``csharprepl`` like:: > for (int i = 1; i < 5; i++) { Console.WriteLine(i); } 1 2 3 4 Now let us make the output neater by using the format string (:ref:`format-strings`) and the ``Console.Write()`` method:: > for (int i = 1; i <= 5; i++) { Console.WriteLine("{0}, ", i); } 1 2 3 4 5 Step in loop header --------------------- ``i++`` is a common pattern and it increments by 1. Also common in the iterator/step section of the loop header is using assignment statement to control stepping:: i = i + k; or the equivalent short-hand compound assignment operator:: i += k; This means to increment the variable i by k. .. index:: operator; += -= *= /= %= single: += operator single: -= operator single: *= operator single: /= operator single: %= operator Most C# binary operations have a similar variation. For instance if *op* is ``+``, ``-``, ``*``, ``/`` or ``%``, **variable** *op*\ = *expression* means the same as **variable** = **variable** op *expression* For example :: x *= 5; is the same as :: x = x * 5; .. index:: format; field width and precision field width formatting precision; format table formatting right justification justification; right single: { }; format field width and precision .. _tables: Formatting Tables ------------------- Reports commonly include tables, often with successive lines generated by a consistent formula and therefore a good example for coding. As a simple first table, we can show the square, cube, and square root of numbers 1 through 10. The Math class has a method ``Sqrt``, so we take the square root with the ``Math.Sqrt`` method. The pattern is consistent, so we can loop easily:: for ( int n = 1; n <= 10; n++) { Console.WriteLine("{0} {1} {2} {3}", n, n*n, n*n*n, Math.Sqrt(n)); } The numbers will be there, but the output is not pretty: .. code-block:: none 1 1 1 1 2 4 8 1.4142135623731 3 9 27 1.73205080756888 4 16 64 2 5 25 125 2.23606797749979 6 36 216 2.44948974278318 7 49 343 2.64575131106459 8 64 512 2.82842712474619 9 81 729 3 10 100 1000 3.16227766016838 First we might not need all those digits in the square root approximations. We can replace ``{3}`` by ``{3:F4}`` to just show 4 decimal places. We can adjust the spacing to make nice columns by using a further formatting option. The longest entries are all in the last row, where they take up, 2, 3, 4, and 6 columns (for 3.1623). Change the format string:: for ( int n = 1; n <= 10; n++) { Console.WriteLine("{0,2} {1,3} {2,4} {3,6:F4}", n, n*n, n*n*n, Math.Sqrt(n)); } and we generate the neater output: .. code-block:: none 1 1 1 1.0000 2 4 8 1.4142 3 9 27 1.7321 4 16 64 2.0000 5 25 125 2.2361 6 36 216 2.4495 7 49 343 2.6458 8 64 512 2.8284 9 81 729 3.0000 10 100 1000 3.1623 We are using two new formatting forms: | ``{``\ index\ ``,``\ fieldWidth\ ``}`` and | ``{``\ index\ ``,``\ fieldWidth\ ``:F``\ #\ ``}`` where index, fieldWidth, and # are replaces by specific literal integers. The new part with the comma (not colon) and fieldWidth, sets the *minimum* number of columns used for the substituted string, padding with blanks as needed. *If the string to be inserted is wider than the fieldWidth,* then the *whole* string is inserted, *ignoring* the fieldWidth. For example:: string s = "stuff"; Console.WriteLine("123456789"); Console.WriteLine("{0,9}\n{0,7}\n{0,5}\n{0,3}", s); generates: .. code-block:: none 123456789 stuff stuff stuff stuff filling 9, 7, and then 5 columns, by padding with 4, 2, and 0 blanks. *The last line sticks out past the proposed 3-column fieldWidth.* One more thing to add to our power table is a heading. We might want: .. code-block:: none n square cube root To make the data line up with the heading titles, we can expand the columns, with code in example:: Console.WriteLine("{0,2}{1,7}{2,5}{3,7}", "n", "square", "cube", "root"); for ( int n = 1; n <= 10; n++) { Console.WriteLine("{0,2}{1,7}{2,5}{3,7:F4}", n, n*n, n*n*n, Math.Sqrt(n)); } generating the output: .. code-block:: none n square cube root 1 1 1 1.0000 2 4 8 1.4142 3 9 27 1.7321 4 16 64 2.0000 5 25 125 2.2361 6 36 216 2.4495 7 49 343 2.6458 8 64 512 2.8284 9 81 729 3.0000 10 100 1000 3.1623 Note how we make sure the columns are consistent in the heading and further rows: We used a format string for the headings with the same field widths as in the body of the table. A separate variation: We also reduced the length of the format string by putting all the substitution expressions in braces right beside each other, and generate the space between columns with a larger field width. .. index:: string; reverse reverse string example; .. _reverse-string-returned: Reversed String Print ---------------------------- Create a method, call it ReverseStringPrint, that, when called with a string, will print the string reversed. We know we could use a ``for`` loop to print the characters in a string reversely. Let us consider the following tools we have: - A string is an array of combined characters with indices. - An array is 0-based. The first character of a string str can be accessed as str[0] - To reverse a string, we need to start from the last indexed character. - The last index number of string ``str`` is related to the length of the string: ``str.Length``. - To process the whole string, we can use the decrement assignment operator (``--``) to start the printing from the end of the string. I managed to come up with some variation of code as below but am running into some errors:: > string s = "drab"; for (int i = s.Length; i >= 0; i++) { Console.Write(s[i]); } bard > One of the errors I see is the famous Index-Out-Of-Range error: .. code-block:: console ┌──────────IndexOutOfRangeException──────────┐ │ Index was outside the bounds of the array. │ └────────────────────────────────────────────┘ Reversed String Return ---------------------------- reversed. Logically, you will perform two separate ideas: reversing a string and printing it. Now consider the first part as its own method:: // this is a method return a string `s` in reverse order. // say, if s is "drab", return "bard". // below is the possible form of the header for the method static string Reverse (string s) In the Reverse method, use a ``for`` loop:: for (int i = s.Length - 1; i >= 0; i--) { A significant idea here is that, instead of immediately printing the ``char``'s, you need to return a reversed string. That means, you need to create a single string, with all the characters, before returning the result. Let us think about this: If you start with ``s`` as ``"drab"``, and you go through the letters one at a time in reverse order, b a r d, you build up successively: .. code-block:: none b ba bar bard You need a loop with variables and operations. The sequence of reversed letters, ``s[i]``, are the last character on the end of each line above. We need a name for the initial part. I used the name ``rev``. Combining with a string is done with the ``+`` operator. Then when ``rev`` is ``"ba"`` and ``s[i]`` is ``'r'``, the combination, using the variable names, is :: rev + s[i] We want this in our loop, so we must be able to use that expression *each* time through the loop, so ``rev`` changes each time through the loop. In the next iteration ``rev`` is the *result* of the previous expression. The assignment statement to give us the next version of ``rev`` can just be:: rev = rev + s[i]; That gives us the general rule. Pay attention now to the beginning and end: The end is simple: The last value for ``rev`` is the complete reversed string, so that is what we return. How do we initialize ``rev``? You could imagine ``rev`` starting as ``"b"``, but the the first character that we add is ``'a'``, and we would not be going through all the characters in our loop. It is better to go all the way back to the beginning: If we use the general form with the first letter in the reversed sequence, :: rev = rev + s[i]; then the result of the initial ``rev`` + ``'b'`` should just be ``"b"``. So what would ``rev`` be? Remember the empty string: initialize ``rev`` to be ``""``. The result is: .. literalinclude:: ../../examples/introcs/reversed_string/reversed_string.cs :start-after: chunk :end-before: chunk :dedent: 6 We used our new operator ``+=`` to be more concise. This function and a ``Main`` used to demonstrate it are in `here `_.