5.3. for
Statement Examples
5.3.1. 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 (Composite formatting) and
the Console.Write()
method:
> for (int i = 1; i <= 5; i++)
{
Console.WriteLine("{0}, ", i);
}
1 2 3 4 5
5.3.2. 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.
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;
5.3.3. 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:
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:
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:
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:
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:
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.
5.3.4. 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:
┌──────────IndexOutOfRangeException──────────┐
│ Index was outside the bounds of the array. │
└────────────────────────────────────────────┘
5.3.5. 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:
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:
/// Return s in reverse order.
/// If s is "drab", return "bard".
static string Reverse (string s)
{
string rev = "";
for (int i = s.Length - 1; i >= 0; i--) {
rev += s[i];
}
return rev;
}
We used our new operator +=
to be more concise.
This function and a Main
used to demonstrate it are in
here.