Module 1: Conditionals


Objectives

 

By the end of this module, for simple programs with real numbers, you will be able to:

Note: this module is perhaps one of the most important so far. It combines four of the most useful building blocks of programming: variables, arrays, conditionals and arrays. Thus, make sure you work through all the details in the (yes, many) exercises.
 

1.0 Audio:
 


1.0    A simple example

 

Consider this program:

 

1.1 Exercise: In MyIfExample.java, add an additional println right below the "Hey, ..." println. Compile and execute the program. Then, change the value of y to 6 and compile/execute. What is the output?
 

About the if-statement:

  • The if-statement above consists of several parts:
    • The reserved word if:

    • The condition (x>y)

    • The block of code associated with the if:

  • Execution:
    • The condition (x>y) is evaluated.

    • If it turns out to be true at the moment the condition executes, the statements inside the if-block are executed.

    • Then, execution continues after the block:

  • If such a condition is not true, execution jumps to just after the if-block.

 

1.2 Exercise: Consider this (part of a) program. Try to mentally execute and identify the output (in module1.pdf) before confirming in MyIfExample2.java,

        int s = 0;
        for (int i=1; i<=5; i++) {
            s = s + i;
        }
        if (s < 15) {
            System.out.println ("Less than 15");		
        }
        System.out.println ("End");
     
 


1.1    If-else

 

Consider this program:

  • If the if-condition (x>y) evaluates to true, the if-block executes:

  • Otherwise, the else block executes:

 

We can combine an else clause with an added if-clause:

  • If the if condition is true, only the if-block executes:

  • If not, the else-if condition is evaluated:

  • If that's true, the appropriate block is executed:

  • If the second if-condition is false, the last else-clause executes:

 

1.3 Exercise: Type up the above example in IfElseExample.java, and change the values of x one at a time so that you see each block execute. That is, try one value of x to make the if-block execute, then another value of x to make the else-if block execute etc.
 

Comparison operators:

  • These are Java's comparison operators:
           (x < y)                // Strictly less than.
           (x <= y)               // Less than or equal to.
           (x > y)                // Strictly greater than.
           (x >= y)               // Greater than or equal to.
           (x == y)               // Equal to.
           (x != y)               // Not equal to.
         

  • Thus, in the above example, we could have written:

 

1.4 Exercise: Are there any circumstances under which the last block executes?
 

  • Here, logic dictates that only some blocks can possibly execute.

  • Thus, sometimes it is not necessary to write some blocks of code if they'll never execute.
 

1.5 Exercise: Suppose we want to identify whether x has the largest value among x, y and z. What is the logical error in the following program?

Can you alter the program (in MyThreeVariableExample.java) to make it work?
 


1.2    Nested conditionals

 

Consider this program:

  • First, the outer if condition is evaluated:

  • Since that's true here, we get inside the if block:

  • The next thing to be executed is the inner if condition:

  • Since that's true here, we get inside that if-statement's if-block:

  • Note how execution goes from there:

 

1.6 Exercise: In MySmallestOfThree.java, modify the above program so that it prints out, appropriately, one of "a is the smallest", "b is the smallest" or "c is the smallest", depending on the actual values of a, b and c. Try different values of these variables to make sure your program is working correctly.
 

1.7 Video:

 


1.3    Combining conditions

 

Consider this program:

  • The if condition combines two comparisons:

  • The combination uses the Boolean operator &&

    • Read && as "AND".

  • The "AND" operator works like this:

    • The overall combination evaluates to true only when BOTH the individual conditions are true.
 

1.8 Exercise: Let's go back to this program:

In MySmallestOfThree2.java, use a two-subclause if-statement to identify whether a is the smallest of the three.
 

1.9 Exercise: In MySmallestOfThree3.java, extend this idea to identify which of the three variables has the smallest value.
 

1.10 Video:

 

The OR operator:

  • Here, the || operator should be read as "OR".

  • If either subclause is true, the whole is true:

  • Note: both sub-clauses can be true, which would make the whole expression true.
 

The NOT operator:

 

1.11 Exercise: In MyNotExample.java, modify the above to determine whether all three variables have different values (no two of them have the same value).
 

The NOT operator can be applied to a larger clause made of sub-clauses:

  • Here, the inner clauses are first evaluated, and the result is "flipped" to see if the NOT clause turns out to be true:

 

1.12 Exercise: Suppose integer variables a,b,c,d,e have values a=1, b=1, c=3, d=4, e=5. Consider the following three expressions:

	( (a <= b) && (c+d > e) && (d > 1) )

        ( (a > c) || ( (c+1 < e) && (c-b > a) ) )

        ! ( (b == d-c) && (a > b) || (c < d) )
     
Try to evaluate each expression by hand. Then, in ExpressionExamples.java, write up each of these in an if-statement to see if the result matches with your hand-evaluation.
 


1.4    Conditionals and loops

 

We'll write a program to loop through a range of numbers, print the even ones:

 

1.13 Exercise: In module1.pdf, trace through the above program as i changes in the for-loop.
 

1.14 Exercise: The above program only prints whether i is even. In OddOrEven.java, modify the above program to print, for every i whether i is odd or whether it's even.
 

In the next example, we'll find the minimum of a function (approximately):

  • Consider the function f(x) = 20 + 100(x3 - x2) in the range [0,1].

  • Let's write a program to find its minimum value in the range:
    
    public class FunctionMinimum {
    
        public static void main (String[] argv)
        {
    	double min = 100;
    	
    	for (double x=0; x<=1; x+=0.1) {
    	    double f = 20 + 100 * (x*x*x - x*x);
    	    if (f < min) {
    		min = f;
    	    }
    	}
    
    	System.out.println ("min value of f = " + min);
        }
    
    }
         
 

1.15 Exercise: In MyFunctionMinimum.java, add a println inside the loop to print the current value of x and f each time it's calculated. What is the value of x at which the minimum of f occurs?
 

1.16 Exercise: In MyFunctionMinimum2.java, modify the above program so that outside the loop, you print both the minimum f as well as the x value where the minimum occurs.
 

1.17 Exercise: What would happen if min were set to 0 outside the loop?
 

1.18 Exercise: Write code in FunctionMinMax.java to print both the minimum and maximum values of f in the range 0 to 1, as well as the x values where the minimum and maximum occur.
 


1.5    Conditionals and arrays

 

Consider this example:

The program adds up the non-negative elements in the array.
 

1.19 Exercise: In module1.pdf, trace through i and sum in the above example.
 

1.20 Exercise: In SearchArray.java, write a program using the same array as above that does the following: it searches the array for a given integer and prints out whether the search was successful.

    public static void main (String[] argv)
    {
        int[] A = {-5, 2, 3, -9, 12, 4, -30};

	int searchItem = 4;

        // Write your loop-and-conditional here:

    }        
     
For example, suppose we want to search a given array to see if it has the element 4. Then, for the above array, the output should be "Yes, 4 exists in the array". If the search item is 5, it should print "heck, no. 5 is not in the array".
 

Minimum and maximum elements in an array:

  • This is often a useful thing: to find the range of some given data.

  • As we'll see, it is also something that will help in sorting data.

  • Here's a first attempt at finding the maximum:

 

1.21 Exercise: In module1.pdf, trace the values of i and max through the above program. Can you think of an array that would cause the program to fail to find the maximum? How would you fix the problem?
 

  • Now, let's add the minimum:

 

1.22 Exercise: Again, find an array for which the above will not work and fix the problem. Write your fixed code in MyMinMaxArray.java.
 

1.23 Exercise: Suppose we had used an else-if as below.

In module1.pdf, trace through the program to see if this works. Then, change the value of the first element of the array to -50 and trace again. Explain what went wrong and how to address the issue.
 

1.24 Exercise: Consider this version:

In module1.pdf, trace through the program to see if this works. Try it with the first array value as -50. Would this work if we had initialized min and max to any element of the array, such as A[3]?
 

1.25 Audio:
 


1.6    Working with more than one array

 

Let's write a simple program to copy one array (of numbers) into another, ensuring that if a number is negative, we copy its positive part:

  • Note: we created array B of the same length as A.

  • No additional condition was needed in the else-clause.
 

Now, we'll do something a little harder: copy over only those elements that are positive:

This type of code is very typical of "clean up" code when processing data.
 

1.26 Exercise: In module1.pdf, trace through the above program to see how it works. Draw a picture showing the contents of array B at each step. Then, modify the program so that it prints only the elements copied over into B.
 

1.27 Exercise: Add code to the template below (in CopyMultiples.java) so that you copy over into B only those numbers from A that are multiples of 3 or 4. Then print out these resulting numbers from array B.

Thus, you should print out: 9, 12, 4, 3, 8, 30.
 

1.28 Exercise: Notice that we copy over fewer elements into B and thus, space is wasted in B. Modify the above (in CopyMultiples2.java) so that you not only copy over into B only those numbers from A that are multiples of 3 or 4, but that B is of the right size (has only the numbers copied over). To do this, you'll first have to count how many numbers will be copied over, then make the array B and then copy over elements. Lastly, print out B.
 

1.29 Video:

 

The examples above are typical of the nuts-and-bolts of working with arrays and data. Working through these examples can feel a bit tedious but constitutes essential practice with arrays.
 


1.7    Nested for-loops

 

Now we'll look at a few examples of working with arrays and conditionals in nested loops.
 

First, let's examine an array to see if it has duplicates:

 

1.30 Exercise: In module1.pdf, trace through the above program, drawing a picture of the array and tracking i and j.
 

1.31 Video:

 

Note:

  • First, notice the starting value for j:

  • Next, notice that the two loop entry conditions are different:

  • This is a "standard" form of nested-loop that allows all possible pairs of elements to be compared.
 

Next, we'll write a program to simply count occurences of each integer in an array:

 

1.32 Exercise: In module1.pdf, trace through the above program, drawing a picture of the occurenceCount array and tracking its values. Do you see why we need max+1 as the size for the occurenceCount array?
 

  • Notice how we used an array value as an index:

  • The output above resulted in printing the occurence count multiple times for some integers.

  • Here's one way to address the problem:
    
        public static void main (String[] argv)
        {
            int[] A = {2, 9, 2, 6, 4, 3, 3, 2};
            int max = 9;
            int[] occurenceCount = new int [max+1];
            for (int i=0; i<A.length; i++) {
                occurenceCount[A[i]] ++;
            }
            for (int k=0; k<occurenceCount.length; k++) {
                if (occurenceCount[k] > 0) {
                    System.out.println (k + " occurs " + occurenceCount[k] + " times");
                }
            }
        }
         
 

1.33 Exercise: Execute the above program (in MyOccurenceCount.java) to see how it works. Then, (in module1.pdf) trace through the second for-loop above.

Note:

  • We're only printing a count for those elements that occur at least once.

  • We've used a different for-loop variable in the second loop. This is strictly not necessary. We could have had
            for (int i=0; i<occurenceCount.length; i++) {
                if (occurenceCount[i] > 0) {
                    System.out.println (i + " occurs " + occurenceCount[i] + " times");
                }
            }
         
    But it's good style to use a different variable name to alert the reader that the meaning of the variable is different.

  • We've replaced the multiple print's with a single println that combines strings and numbers (into a larger string).

  • In the above programs, we manually look at the array A and wrote down the maximum value (9) in the code ourselves
            int max = 9;
         

  • This is an example of what's called hard coding:
    • The term is used as the verb, to hard code.
    • It refers to actual data in the code that's fixed ahead of time.
    • It's generally NOT a good idea.
    • Here, we're doing this for simplicity of explanation.
    • In a real application, we would not know the contents of of the array ahead of time.

  • It's easy to fix this by writing code to find the maximum.
 

1.34 Exercise: In MyOccurenceCount2.java, replace the hard-coded max with code that finds the maximum of the array A.
 

Searching the elements of one array in another:

  • This is a very common operation in processing data:
    • We have existing data.
    • New data comes in, and we want to see which of the new data already exists.

  • In our example, suppose we have
    	int[] recentData = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
    	int[] existingData = {2, 3, 5, 7, 11, 13, 17, 19};
         

  • As output, we want to print 3, 5, 7, 11, 13, 17, 19.

  • Thinking at a high (pseudocode) level, we want something like:
         for i=0 ... (the first array) {
             // Look for this i-th element in the second array
             for j=0 ... (try each element of the second) {
                 if i-th of first == j-th of second {
                     // Found!
                 }
             }
         }
         
 

1.35 Exercise: In TwoArraySearch.java, write code to use the above data and solve the problem.
 

1.36 Video:

 


1.8    Rearranging an array

 

Rearranging elements in an array is the basis of sorting, one of the most common and powerful ways of organizing data.

  • We don't sort data just because it looks nice sorted.

  • Sorted data greatly speeds up the execution of other kinds of code.

  • For example, it's much faster to search for something in sorted data.
 

We'll start with something simpler: find the smallest value in an array and move it to the first location in the array.

 

The program:

 

1.37 Exercise: Write up and execute the above program in MoveMin.java. Then, trace through the first for-loop above. What would happen we started with i=0 in that for-loop?
 

1.38 Video:

 

1.39 Exercise: In MoveMin2.java. add code to the above program so that, after the min element is moved to position 0, the next smallest element (one of the 1's above) is moved into position 1.

Change the data in the array several times to see if your program works.
 

We'll now generalize this idea to move the k-th smallest element to the k-th position:

	int[] A = {13, 5, 2, 0, 1, 3, 21, 1, 8};
	
	for (int k=0; k<A.length-1; k++) {
	    
	    // Default assumption: k-th element is k-th min.
	    int min = A[k];
	    int minPosition = k;

	    // Now find the min amongst elements from
            // positions k onwards.
	    for (int i=k+1; i<A.length; i++) {
		if (A[i] < min) {
		    min = A[i];
		    minPosition = i;
		}
	    }

	    // Swap min into position k.
	    int temp = A[k];
	    A[k] = A[minPosition];
	    A[minPosition] = temp;
	}

	// Print.
	for (int i=0; i<A.length; i++) {
	    System.out.println (A[i]);
	}
     
 

1.40 Exercise: In module1.pdf, trace the values of these variables: k, i, min and minPosition. Then, execute the above program (in MoveMin3.java) to see the result. What is the result? What have we achieved?
 

1.41 Exercise: Is the variable min really needed? Re-write the program (in MoveMin4.java) to do without it (but using the other variables).
 

1.42 Audio:
 

1.43 Exercise: Write a variation of the above program (in MoveMax.java) so that the maximum element is swapped into the first place (position 0), then the next largest is swapped in the second place (position 1) ... etc.
 


1.9    Reading and writing

 

First, reading:

  • When seeing

    say to yourself:

    • "Here's an if-block that may or may not execute."
    • "What follows the if-block (the second println) always executes".

  • Read aloud the if-construct as: "if x > y then ... (the first println)".

  • Similarly when seeing a larger if-else, focus on the structure:

    Say to yourself:

    • "Only one of the three code blocks will execute."
    • "The second condition is evaluated only if the first one is false."
    • "We reach the third block only if both the previous two conditions fail."

  • When seeing a complex condition like

    break it up into a hierarchical view:

 

1.44 Exercise: In module1.pdf, draw a hierarchical picture that matches the conditional below.

	int x = 5, y = 4, z = 6;

	if ( ((z < 0) || (z > 1)) && (!(x < y)) || (!(x < z)) ) {

	    // ...
	}
     
Then, evaluate it to see whether the result is true or false. Write down the true/false values at intermediate levels of the hierarchy.
 

Writing:

  • Remember to type in the matching right bracket immediately after typing in the left one.
  • Use spacing and layout consistent with the above example.
 


1.10    When things go wrong

 

 

1.45 Exercise: In module1.pdf, identify the four errors in this piece of code:

 

1.46 Exercise: Fix the errors in the if condition to make this print "Success".

First, try to find the problems without compiling. Then, fix the code (in Ex1_46.java ) and see if you were right while reading.
 

1.47 Exercise: What does the following print out?

Fix the problem (in Ex1_47.java).
 

1.48 Exercise: The following code intends to print out alternate array elements starting from the end, but only if the elements aren't negative.

However, there are two problems. Can you see the problems just by reading? Fix the problems (in Ex1_48.java).
 

1.49 Exercise: The following code intends to search an array for a given searchValue to print true or false, depending on whether it was found or not.

Trace through the above program by hand (in module1.pdf). to predict what it prints. Then, fix the problem (in Ex1_49.java).
 

1.50 Audio:
 


1.11    Meta

 

This has been a challenging module: intricate code, with many moving parts, and looooong. A few things to keep in mind:

  • It is exactly this type of intricate detail that needs to be mastered and is critical to developing "code-like thinking".

  • It is natural and perfectly acceptable to feel overwhelmed by the sheer amount of detail. All those traces! The loops! The arrays!

  • At the present moment it will certainly feel that way.

  • By the end of the course, you will be able to come back to this module and feel a lot better about it.

  • Many units later (say, after unit 6), this will all seem rather easy, and you'll wonder why you ever thought it was tough.

  • This is simply the nature of how complex skills are learned.
 

1.51 Audio:


On to Module 2



© 2017, Rahul Simha