Week 07 General Practice

Please Enter Your Shipping Details:

Shipping Options

Pick the most important date and time

Choose a file for enjoyment:

JavaScript Practice

The following JavaScript file contains the code detailed below. Paste the code in any JS console, including your browser console ([F12] in Firefox), and run to see output. JS file: Week 07 JS Practice

The Ternary Operator

The ternary operator provides a more concise way to write a basic if-else function in form: if-condition-true : do-this ? if-not-do-this-instead. Here it is used it to replicate the functionality of the Math.min() function, which checks which number of two parameters is smaller.

      
        function mathmin(x, y) {
          x < y ? console.log(x + " is less than " + y) : console.log(y + " is less than " + x)
        }
        mathmin(10, 20);
        mathmin(80, 100);
      
    

Output:

      
        10 is less than 20
        80 is less than 100
      
    

Loops

The for loop in JavaScript has identical syntax to Java. It takes up to three arguments and states, "given initial w; check condition y and run body if true; then update this after body runs". Here a for loop iterates through an integer i starting at value 0, on each iteration printing a String of #, where the number of # per iteration is equal to the size of i. At the end of the iteration, it increases i by 1, and stops when i grows to greater than 6. The result is a triangle of #.

JavaScript also includes standard while and do while loops, stating "while x condition is true, do y statement(s)" and "do y statement(s), while x condition is true", respectively. The difference is that in the do while loop, the enclosed statement(s) will be executed at least once, prior to the while condition being checked for the first iteration, as the intial do runs before the while is checked.

      
        console.log("//A triangle of #");
        let hash = "";
        for (let i = 0; i < 7; i++) {
          hash += "#";
          console.log(hash);
        }
      
    

Output:

      
        #
        ##
        ###
        ####
        #####
        ######
        #######
      
    

if-else Statements

Like loops, the if-else statement is another rudimentary piece of programming logic. It states, "if condition y, do x, else, do z." It can also be composed using the "else if" checks, in which case the logic is, "if condition y, do x, else if condition w, do z, (optional) else, do p." Here I use if-else inside a loop to perform the classic FIZZBUZZ exercise, up to integer 50:

      
        for (let i = 1; i <= 25; i++) {
          if (i % 3 == 0 && i % 5 == 0)
            console.log(i + ": " + "FIZZBUZZ");
          else if (i % 3 == 0)
            console.log(i + ": " + "FIZZ");
          else if (i % 5 == 0)
            console.log(i + ": " + "BUZZ");
        }
      
    

Output:

      
        3: FIZZ
        5: BUZZ
        6: FIZZ
        9: FIZZ
        10: BUZZ
        12: FIZZ
        15: FIZZBUZZ
        18: FIZZ
        20: BUZZ
        21: FIZZ
        24: FIZZ
        25: BUZZ
        27: FIZZ
        30: FIZZBUZZ
        33: FIZZ
        35: BUZZ
        36: FIZZ
        39: FIZZ
        40: BUZZ
        42: FIZZ
        45: FIZZBUZZ
        48: FIZZ
        50: BUZZ
      
    

Nesting Loops

When logic is nested, the program is declaring a scope within a scope, logic within logic. You can nest classes within classes, functions within functions, loops within loops within loops within loops, and so forth. Here I print checkboards of #, first with nested for loops, then a slightly smaller checkboard with nested while loops. For each iteration of the outer loops, the inner loops will iterate until stopped when their exit condition is met, then continue for a new set of iterations on the next iteration of the outer loops, resetting the checkerboard row String at the end of each iteration of the outer loops.

      
        let endHeightF = 8,
          endWidthF = 10,
          row = "";

        for (let height = 0; height < endHeightF; height++) {
          for (let width = 0; width < endWidthF; width++) {
            if ((height + width) % 2 == 0)
              row += " ";
            else
              row += "#";
          }
          console.log(row);
          row = "";
        }
      
    

Output:

      
        # # # # #
       # # # # #
        # # # # #
       # # # # #
        # # # # #
       # # # # #
        # # # # #
       # # # # #
      
    
      
        let currentWidth = 0,
          currentHeight = 0,
          gridRow = "";

        while (currentHeight < 8) {
          while (currentWidth < 8) {
            currentWidth++;
            if ((currentHeight + currentWidth) % 2 == 0)
              gridRow += "#";
            else
              gridRow += " ";
          }
          console.log(gridRow);
          currentHeight++;
          currentWidth = 0;
          gridRow = "";
        }
      
    

Output:

      
        # # # #
       # # # #
        # # # #
       # # # #
        # # # #
       # # # #
        # # # #
       # # # #
      
    

Recursive Calls

In a recursive call, a function calls itself. In such cases, a condition is tested where until met the function will condition to call itself, executing whatever logic it encloses along the way. When the exit condition is met, the recursion stops, and a final value is returned back through the stack of the recursive calls.

While recursion provides an elegant way to perform complex logic and can be much less wordy than writing functions with traditional loops, if statements, etc., it should also be noted that using recursion often comes with a significant impact on execution speed. Choosing when and when not to use recursion should thus be carefully decided, such as using it when traversing through branched data structures, but not in a less complex situation, such as simply traveling through array indexes and running a basic expression on the index values.

Here I define an evenOdd() function to determine if a passed whole number is even or odd, without using the mod operator. The number passed to this function travels through a chain of recursive calls, subtracting 2 from its value on each call, until it either equals 0 (even) or 1 (odd). If a negative or decimal number is passed, the function returns a -1, indicating an input error. I also built a simple print function, to print the results in a user readable format.

      
        function evenOdd(num) {
          if (num == 1)
            return 1;
          else if (num == 0)
            return 0;
          else if (num < 0)
            return -1;
          else
            return evenOdd(num - 2);
        }

        function printEvenOdd(num) {
          if (evenOdd(num) == 0)
            console.log(num + " is even.");
          else if (evenOdd(num) == 1)
            console.log(num + " is odd.");
          else
            console.log(num + ": Please no negative or decimal numbers.");
        }

        printEvenOdd(10, 10);
        printEvenOdd(23, 23);
        printEvenOdd(-5, -5);
      
    

Output:

      
        10 is even.
        23 is odd.
        -5: Please no negative or decimal numbers.
      
    

String Counting Chars

In JavaScript Strings implement the iterable interface and thus can be accessed and manipulated similar to how array interaction can be done. Here a simple function checks for how many times a specified char occurs in a passed String. Longer substrings can quickly be detected and copied out via functions String.indexOf() and String.slice()

      
        function countChar(cString, char) {
          let cCount = 0;
          for (let i = 0; i < cString.length; i++) {
            if (cString[i] === char)
              cCount++;
          }
          console.log("\"" + cString + "\" has " + cCount + char + "'s.");
        }
      
    

Output:

      
        "Bobby Bradsworth lives in Bolivia." has 3B's.
      
    

Experiment with Objects & foreach()

Here I experiment with objects, defining anonymous objects as elements of an array, then accessing the objects' properties using the ES6 addition for...of() function, which allows shorthand for the traditional for statement via logic "for each index in this array,{ /*execute these statements*/}

      
        let customerQueue = [{
            name: "Charles",
            mostExpensive: 29.99,
            leastExpensive: 9.49,
            numberItems: 12
          },
          {
            name: "Diana",
            mostExpensive: 97.23,
            leastExpensive: 14.73,
            numberItems: 21
          },
          {
            name: "Junto",
            mostExpensive: 37.23,
            leastExpensive: 24.73,
            numberItems: 16
          },
          {
            name: "Sergio",
            mostExpensive: 17.23,
            leastExpensive: 5.73,
            numberItems: 17
          }
        ];

        function printCustomers(custQueue) {
          for (let customer of custQueue)
            console.log(customer.name);
        }

        console.log("You have three customers in line: ");
        printCustomers(customerQueue, "name");
        newLine();

      
    

Output:

      
        You have three customers in line:
        Charles
        Diana
        Junto
        Sergio
        Number of items in all carts: 66
      
    

A Range of Numbers

A function to generate a range of numbers, with an optional step parameter that increases numbers in step intervals, stored in an array. Also a function to sum the range items. Added error messages to display when invalid input entered. Utilizes Array.push()

      
        function range(start, end, step) {

          if (!(wholeNumber(start) || !(wholeNumber(end)))
            return;

          let rangeArray = [];

          if (step == undefined) {
            while(start <= end) {
              rangeArray.push(start);
              start++;
            }
            console.log("Created range: " + rangeArray);
          } else {
            if (!(wholeNumber(step)))
              return;

            if (step > (end - start)) {
              console.log("Step too large for range. Please enter smaller step or increase range.")
              return;
            }
            while (start <= end) {
              rangeArray.push(start);
              start += step;
            }
            console.log("Created step range: " + rangeArray);
          }
          return rangeArray;
        }

        //6 - sums array of numbers
        function sumArray(numArray) {
          let sum = 0;

          for (num of numArray)
            sum += num;

          return sum;
      
    

Output:

      
        Created range: 1,2,3,4,5,6,7,8,9,10
        Sum of range: 55


        Created range: -10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10


        Creating range: fish to 20.
        Please only whole numbers. "fish" is not acceptable.


        Creating range: 20 to 100.2384.
        Please only whole numbers. "100.2384" is not acceptable.


        Created step range: 1,6,11,16,21,26,31,36,41,46,51,56,61,66,71,76,81,86,91,96
        Sum of range: 970


        Creating range: 10 to 20 with 30 step.
        Step too large for range. Please enter smaller step or increase range.
      
    

Reverse Array

The JavaScript Array prototype has some useful methods for adding and removing objects. push() and pop() add and remove from the end of the array(note the function names as commonly also used by stacks). shift() and unshift() allow addition and deletion from the start of an array, and allow the array to be used as a queue.

In the first reversal function, I return a reversed version of the passed array by traversing through it and pulling off items from the start via unshift(), then add them to a new array, which I return.

In the second function, I reverse the array in-place, reversing the original array without creating a new array. I do this without utilizing any Array.prototype functions. The % 2 ternary check here exists to determine if the array holds an even or odd number of elements, to use when telling how many iterations to swap for.

      
        //reverses array by creating new reversed array
        function reverseArray(original) {
          let reversed = [];
          for (index of original)
            reversed.unshift(index);
          return reversed;
        }

        function reverseArrayInPlace(original) {
          let temp,
            iterations;

          (original.length % 2) == 0 ? iterations = original.length / 2 : iterations = ((original.length / 2) - 1);

          for (let i = 0; i < iterations; i++) {
            temp = original[i];
            original[i] = original[original.length - 1 - i];
            original[original.length - 1 - i] = temp;
          }
          return original;
        }

        let originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        console.log("Original array: " + originalArray);
        console.log("New reversed array: " + reverseArray(originalArray));
        console.log("Original array reversed in place: " + reverseArrayInPlace(originalArray));

        newLine();
      
    
      
        Original array: 1,2,3,4,5,6,7,8,9,10
        New reversed array: 10,9,8,7,6,5,4,3,2,1
        Original array reversed in place: 10,9,8,7,6,5,4,3,2,1
      
    

Create a List from an Array

In a traditional list data structure, a list is a collection of nodes, where each node is linked to the next node (with both to and from pointers in a doubly linkedlist). Here I provide a method to turn an array into a list. I then add a method to revert the list back to an array. The prepend() function adds an element to the start of the list. nthNode() returns a specified node using a loop, while nthNodeRecursive (can you guess?), does the same, but through recursion.

      
        //Turns array into list
        function arrayToList(theArray) {
          let list = null;

          for (let i = theArray.length - 1; i >= 0; i--)
            list = {
              value: theArray[i],
              link: list
            };
          return list;
        }

        //Turns list into array
        function listToArray(theList) {
          let array = [];

          for (node = theList; node != undefined; node = theList) {
            array.push(theList.value);
            theList = theList.link;
          }
          return array;
        }

        //adds element to front of list
        function prepend(element, list) {
          return {
            value: element,
            link: list
          };
        }

        //returns value of nth list node
        function nthNode(theList, index) {
          let count = 0;

          while (count < index - 1 && theList.link != null) {
            theList = theList.link;
            count++;
          }
          return theList.value;
        }

        //returns value of nth list node using recursion
        function nthNodeRecursive(theList, index, count = 0) {
          if (count < index - 1 && listCopy.link != null) {
            return nthNodeRecursive(theList.link, index, count++);
          } else
            return theList.value;
        }

        //prints list values as a string
        function printList(theList) {
          let valueString = ""

          //while loop is a bit wordier than the listToArray() for loop, but the print format is nicer
          while (theList.link != null) {
            valueString += theList.value.toString() + ",";
            theList = theList.link;
          }
          valueString += theList.value.toString() + "";
          console.log("List: " + valueString);
        }
      
    

Input:

      
        let listArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        console.log("Array created: " + listArray);
        let list = arrayToList(listArray);
        console.log("Converting array to list...");
        printList(list);
        console.log();

        console.log("Adding to list...");
        list = prepend(0, list);
        printList(list);
        console.log();

        console.log("Value for node #7: " + nthNode(list, 7));
        console.log("Value for node #4, traversed via recursion: " + nthNode(list, 4));
        console.log();

        console.log("Converted back to array: " + listToArray(list));

        newLine();
      
    

Output:

      
        Original array: 1,2,3,4,5,6,7,8,9,10
        New reversed array: 10,9,8,7,6,5,4,3,2,1
        Original array reversed in place: 10,9,8,7,6,5,4,3,2,1


        Array created: 1,2,3,4,5,6,7,8,9,10
        Converting array to list...
        List: 1,2,3,4,5,6,7,8,9,10

        Adding to list...
        List: 0,1,2,3,4,5,6,7,8,9,10

        Value for node #7: 6
        Value for node #4, traversed via recursion: 3

        Converted back to array: 0,1,2,3,4,5,6,7,8,9,10
      
    

A Deep Compare

Some prototypes, such as primitives and Strings can have their values compared using the == operator. When you use == on objects, it only checks to see if the compared objects share the same identity. Here I create a method to compare objects on a deeper level, where objects are determined as equal only if they share all the same property names and values.

To do this, I first check that both items passed are objects. I then check to make sure the objects passed are not of null value. For pulling data, I utilize the Object.keys() function, which returns an array of all property names in the object, making a second call to Object.keys() for each index to account for properties as objects that contain more properties, etc.. To compare these values, I make a recursive call to deepEqual(), which repeats the typeOf check, and then compares the values and keys in the two innermost if statements. If the loop containing these steps at any time encounters a key or value comparison that returns !=, the function halts and returns false. If it is able to make it through all values and keys as showing ==, it returns true.

      
        function deepEqual(itemA, itemB) {
          if (typeof itemA == typeof itemB) {
            //executes if initial items passed are objects
            if (typeof itemA == "object" && itemA != null) {
              if (Object.keys(itemA).length == Object.keys(itemB).length) {
                for (let i = 0; i < Object.keys(itemA).length; i++) {
                  let keyA = Object.keys(itemA)[i],
                    keyB = Object.keys(itemB)[i];
                  if (deepEqual(keyA, keyB) == false)
                    return false;
                  if (keyA != "object") {
                    if (itemA[keyA] != itemB[keyB]) {
                      return false;
                    }
                  }
                }
                return true;
              }
            }
            //if initial items passed are not objects, this executes
            else {
              if (itemA == itemB)
                return true;
              else
                return false;
            }
          }
        }
      
    

Input:

      
        console.log("Values 12 and 10 are equal? " + deepEqual(12, 10));
        console.log("Values Dog and Dog are equal? " + deepEqual("Dog", "Dog"));

        console.log("Objects {animal: \"Dog\"} and {animal: \"Dog\"} are equal ? " + deepEqual({
          animal: "Dog"
        }, {
          animal: "Dog"
        }));

        console.log("Objects {animal: \"Dog\", age: 10, living: true} and {animal: \"Dog\", age: 10, living: true} are equal? " + deepEqual({
          animal: "Dog",
          age: 10,
          living: true
        }, {
          animal: "Dog",
          age: 10,
          living: true
        }));

        console.log("Objects {animal: \"Dog\", age: 10, living: true} and {animal: \"Dog\", age: 15, living: true} are equal? " + deepEqual({
          animal: "Dog",
          age: 10,
          living: true
        }, {
          animal: "Dog",
          age: 15,
          living: true
        }));

        console.log("Objects {animal: \"Dog\", age: 10, living: true} and {SPACESHIP: \"Dog\", age: 10, living: true} are equal? " + deepEqual({
          animal: "Dog",
          age: 10,
          living: true
        }, {
          SPACESHIP: "Dog",
          age: 10,
          living: true
        }));

      
    

Output:

      
        Values 12 and 10 are equal? false
        Values Dog and Dog are equal? true
        Objects {animal: "Dog"} and {animal: "Dog"} are equal ? true
        Objects {animal: "Dog", age: 10, living: true} and {animal: "Dog", age: 10, living: true} are equal? true
        Objects {animal: "Dog", age: 10, living: true} and {animal: "Dog", age: 15, living: true} are equal? false
        Objects {animal: "Dog", age: 10, living: true} and {REEEEE: "Dog", age: 10, living: true} are equal? false