Discussion, Questions, and Resources for Part 3 of the April 2018 Cohort (Intermediate Algorithm Scripting and JavaScript Algorithms and Data Structures Projects)

Here are the next five solutions:

Sum All Odd Fibonacci Numbers

My first attempt at this resulted in the following:

function sumFibs(num) {
  let fibs = [1, 1];
  let counter = 0;

  while (counter <= num) {
    fibs.push(fibs[counter] + fibs[counter + 1]);
    counter++;
  }

  let subTotal = 0;

  fibs.map(item => {
    if (item <= num) {
      if (item %2 !== 0) subTotal += item;
    } 
  });

  return subTotal;

}

First, this creates a list of fibonacci numbers up to and including the given number. Then it checks each of those numbers to see if it is less than the number given and if the it is odd. If it is less than the given number and odd, it adds it to the subtotal variable. This feels more straightforward, yet possibly not as efficient, as the basic solution in the fCC Guide for Sum All Fibonacci Numbers. The intermidiate solution in the guide lead me to this, using reduce(), which is probably more appropriate here:

function sumFibs(num) {
  let fibs = [1];
  let counter = 1;

  while (counter <= num) {
    fibs.push(counter);
    counter = fibs[fibs.length - 1] + fibs[fibs.length - 2];
  }

  return fibs.reduce((prev, cur) => cur % 2 !== 0 ? prev + cur : prev)
}
Sum All Primes

This one was difficult for me, specifically the part of trying to get a list of prime numbers. I used a StackOverflow answer to generate the primes ā€“ which is similar to the basic solution in the fCC Guide ā€“ and then it was a matter of getting the sum of those numbers:

function sumPrimes(num) {
 let tempArr = [];
  let i, j, primes = [];
    for (i = 2; i <= num; ++i) {
        if (!tempArr[i]) {
            // i has not been marked -- it is prime
            primes.push(i);
            for (j = i << 1; j <= num; j += i) {
                tempArr[j] = true;
            }
        }
    }
    return primes.reduce((prev, next) => prev + next);
}

The intermediate and advanced solutions in the fCC Guide for Sum All Primes are interesting and worth looking at.

Smallest Common Multiple

I needed to rely on StackOverflow again for this one, this time to figure out the greatest common denominator.

function smallestCommons(arr) {
  let sortedArr = arr.sort((a, b) => a - b);
  let fullArr = [];
  
  // Create an array with all necessary numbers
  let counter = sortedArr[0];

  while (counter <= sortedArr[1]) {
    fullArr.push(counter);
    counter++;
  }

  // Borrowed from https://stackoverflow.com/a/17136781
  function gcd(...fullArr) {
    return fullArr.reduce((acc, cur) => cur === 0 ? acc : gcd(cur, acc % cur));
  }

  return fullArr.reduce((acc, cur) => Math.abs(acc * cur) / gcd(acc, cur));
}
Drop It

Now that weā€™re back to less math-heavy challenges, I was able to solve this challenge using map(), indexOf(), and slice():

function dropElements(arr, func) {
  let tempArr = arr.map(item => func(item));
  return tempArr.indexOf(true) !== -1 ? arr.slice(tempArr.indexOf(true)) : [];
}

This first creates a temp array with true/false values based on whether or not the item in the given array is true or false in the given function. Then, if the temp array has a true value, it finds the index of the first ā€˜trueā€™ value and slices the given array at that index, returning everything thereafter. If the temp array doesnā€™t have a true value, it returns an empty array.

The fCC Guide for Drop It has some other ways to solve this challenge.

The basic solution checks the first element of the given array with the given function. If the function returns true, the loop stops and the array is returned from that point. If the function returns false, the first element of the array is removed using shift():

function dropElements(arr, func) {
  var times = arr.length;
  for (var i = 0; i < times; i++) {
    if (func(arr[0])) {
      break;
    } else {
      arr.shift();
    }
  }
  return arr;
}

The intermediate solution is short and sweet. It relies on slice() and the findIndex() function. The findIndex() function returns the index of the element that returns true from the given function. findIndex() will return -1 if it doesnā€™t find an element that returns true, so the ternary operator is used to check for that and either return a sliced array from the first true element to the end of the array or a sliced array that returns an empty array:

function dropElements(arr, func) {
  return arr.slice(arr.findIndex(func) >= 0 ? arr.findIndex(func): arr.length, arr.length);
}

The advanced solution is also short and sweet, but this time using a while loop and shift:

function dropElements(arr, func) {
  while(arr.length > 0 && !func(arr[0])) {
    arr.shift();
  }
  return arr;
}

This is similar to the basic solution in that it removes the first element if itā€™s false, but it uses a while loop and doesnā€™t need to use break to end the loop when an element thatā€™s true is found.

Steamroller

My initial solution is pretty close to the basic solution in the fCC Guide for Steamroller in that I create a function and then use recursion to keep sending arrays into that function until there are no arrays left:

function steamrollArray(arr) {

  let result = [];

  const tempFunc = (inArr) => {
    inArr.map(item => Array.isArray(item) ? tempFunc(item) : result.push(item));
  }

  tempFunc(arr);  
  return result;
}

The intermediate solution is really good. It takes advantage of the spread operator as well as some(). It first initializes a variable named flat that flattens the first level of the array. Then, it uses some() to check for the existence of another array. If another array exists, it recursively runs the function again. If and when another array doesnā€™t exist, it returns the flattened array in the flat variable.

function steamrollArray(arr) {
  let flat = [].concat(...arr);
  return flat.some(Array.isArray) ? steamrollArray(flat) : flat;
}

:sunny:

These definitely made me think. I had to use a pencil and my brain (at the same time no less!) to get through some of these.

Now that Iā€™ve come down from from my functional programming high (some) Iā€™m finding that some things still look clearer to me with classic forā€¦loops, ifā€¦else statements, etc.

Sum All Odd Fibonacci Numbers
function sumFibs(num) {
  const prev = [0,1]
  let accum = 0;
  let next = 1;
  
  while(next <= num){
    
    if(next%2){ accum += next; }// accumulate odds
 
    next = prev[0] + prev[1];
    prev.push(next)
    prev.shift();
  } 
  return accum;
}
Sum All Primes

This makes (and remakes) what can be a huge range array but still ended up being the fastest of my attempts. The larger the number, the larger the range. Yet, the larger the number the more this solution left my others in the dust even with similar number of iterations. Go figure.

Watching console.log output clued me in that I could stop looking for primes at the square root of the given number.


function sumPrimes1(num) {
	// range 2 to num inclusive (1 not prime, skip 1)
	let range = [];

	for (let i = 2; i <= num; i++) {
		range.push(i);
	}

	let stop = Math.ceil(Math.sqrt(num));

	// remove all non-prime from range
	for (let i = 0; range[i] <= stop; i++) {
		const number = range[i];
		//console.log(range[i]);  //always the next prime!
		// remove multiples of range[i] from range
		range = range.filter(el => el % number || el === number);
	}
	// sum all primes
	return range.reduce((acc, cur) => (acc += cur));
}
Smallest Common Multiple

Most important lesson I learned from this challenge is sometimes pencil and paper is the best problem solving tool.

How it works

In the case of [1,5]
LCM of 4 and 5 try 5 - no, try 10 - no, 15 - no, 20 - YES!
LCM of 4 and 5 is 20 so any LCM for range must be a mult of 20 so only check multiples of 20 going forward
LCM of 20 and 3 try 20 - no, try 40 - no, try 60 - yes
LCM of 20 and 3 is 60 so LCM for range must be mult of 60 so only check multiples of 60
LCM of 60 and 2 is 60
LCM of 60 and 1 is 60

function smallestCommons(arr) {
  let smaller = Math.min(...arr);
  let LCM, nextLCM, larger;
  nextLCM = LCM = larger = Math.max(...arr);

  for (let i = larger; i > smaller; i--) {
    while (nextLCM % (i - 1) !== 0) {
      nextLCM += LCM;
    }
    LCM = nextLCM;
  }
  return LCM;
}
Drop It
function dropElements(arr, func) {
  const index = arr.findIndex(func);
  return index !== -1 ? arr.slice(index) : [] ;
}
Steamroller

I kept trying to come up with some array method magic that would make this elegant but nothing was as clear to my eye as a plain Jane ifā€¦else

function steamrollArray(arr) {
	var flattened = [];
	for (let elem of arr) {
		if (Array.isArray(elem)) {
			flattened = flattened.concat(steamrollArray(elem));
		} else {
			flattened.push(elem);
		}
	}
	return flattened;
}
1 Like

@nvrqt03, @camperextraordinaire and @alhazen1, thanks for sharing! Iā€™ve learned a lot from all of your solutions. :fireworks: Reviewing code that more experienced people have written has proven to be really helpful for me.

Here are my final five algorithms:

Binary Agents

I used split(), map(), String.fromCharCode(), parseInt(), and join() for my solution. First the string is split by spaces to create an array of binary numbers. Then, I loop through each binary number using map() and convert each binary number into a letter. Then, join them back togther:

function binaryAgent(str) {
  return str.split(' ').map(binary => String.fromCharCode(parseInt(binary.toString(), 2))).join('');
}

The advanced solution in the fCC Guide for Binary Agents does the same thing, but in a different order. I cleaned it up a little with arrow functions:

const binaryAgent = str => String.fromCharCode(...str.split(" ").map(char => parseInt(char, 2)));

I like this a little better. I always forget that built-in functions can take functions as arguments, so this solution reminds me of this. Also, this is a great use of the spread operator, saving the need for join(). Nice!

Everything Be True

I started with a solution that used Boolean() and indexOf():

const truthCheck = (collection, pre) => collection.map(item => Boolean(item[pre])).indexOf(false) === -1 ? true : false;

Then, I remembered from previous solutions Iā€™ve seen that some() might fit well here, and came up with this which is a little smoother:

const truthCheck = (collection, pre) => collection.some(item => Boolean(item[pre]) === false) ? false : true;

But, then in the fCC Guide for Everything Be True, the advanced solution shows an even more straightforward way to solve this challenge, using only only every(). This checks to see if all elements in the given array pass the test, in this case, all weā€™re looking for is whether the value is truthy:

const truthCheck = (collection, pre) => collection.every(obj => obj[pre]);
Arguments Optional

I used recursion for this one:

const addTogether = (...args) => {
  if (typeof args[0] !== 'number') return;

  return args.length === 1 ? item => addTogether(args[0], item) : typeof args[1] === 'number' ? args[0] + args[1] : undefined;
}

After looking through the fCC Guide for Arguments Optional, I like the recursive way of doing this.

Make a Person

This is my solution:

const Person = function(firstAndLast) {
  
  let [firstName, lastName] = firstAndLast.split(' ');

  this.getFullName = () => `${firstName} ${lastName}`;
  this.getFirstName = () => firstName;
  this.getLastName = () => lastName;
  this.setFirstName = (first) => firstName = first;
  this.setLastName = (last) => lastName = last;
  this.setFullName = (firstAndLast) => [firstName, lastName] = firstAndLast.split(' ');

};

If there are better/more efficient/more readable ways to do this, please share and explain why another way is better. Thanks!

Map the Debris

My solution loops through all of the given objects and creates an orbitalPeriod variable using the formula found on Wikipedia (also in the fCC Guide for Map the Debris) for each object. Then, it deletes the avgAlt property and creates a new orbitalPeriod property for each object:

const orbitalPeriod = arr => {
  var GM = 398600.4418;
  var earthRadius = 6367.4447;
   arr.map(item => {
    const orbitalPeriod = Math.round(2 * Math.PI * Math.sqrt(Math.pow(earthRadius + item.avgAlt, 3) / GM));
    delete item.avgAlt;
    item.orbitalPeriod = orbitalPeriod;
  });
return arr;
};

My solution is similar to the advanced solution in the guide, but the guide uses forEach() instead of map(). What is the advantage of using forEach() over map() in this case?

Thatā€™s it for the intermediate algorithms for me. Now on to the projects! :sunny:

I finished all of the Javascript projects! :fireworks: Hereā€™s the first one with some explanation and a bunch of different ways to solve it:

Palindrome Checker

I started this one out by stripping the given string of all punctation, one symbol at a time. This resulted in a relatively messy regular expression:

const palindrome = str => {
  /* Remove (in order): dashes (-), spaces (\s), underscores (_),
     commas (,), left parenthesis [\(], right parenthesis [\)],
     periods (.), colons (:), bars (\|), and forward slashes (\/).
  */
  let strippedStr = str.replace(/[-\s_,\(\)\.:\|\/]/g, "").toLowerCase();

  return strippedStr === strippedStr.split('').reverse().join('');;
}

In looking at the fCC Guide for Palindrome Checker, I noticed the use of the much simpler \W regular expression and now my solution looks like this:

const palindrome = str => {
  let strippedStr = str.replace(/[\W_]/g, "").toLowerCase();
  return strippedStr === strippedStr.split('').reverse().join('');
}

Then, after reading about the advanced solution in the guide, I learned about using continue and some of the reasons why it might be a good idea to not use so many functions chained together. Iā€™m not sure if Iā€™ll ever need to use this solution for performance reasons, but itā€™s at least nice to know about in case Iā€™m asked something similar in an interview or something like that:

const palindrome = str => {
  let beg = 0;
  let end = str.length - 1;

  while (end > beg) {
    if (str[beg].match(/[\W_]/)) { beg++; continue; }
    if (str[end].match(/[\W_]/)) { end--; continue; }
    if (str[beg].toLowerCase() !== str[end].toLowerCase()) return false
    beg++;
    end--;
  }
  return true;
}

The Two Ways to Check for Palindromes in JavaScript has a good explanation of some solutions.

Hereā€™s an interesting solution that I found in the comments at Palindrome check in Javascript on Stack Overflow. I modified it a little to make it pass the fCC tests:

const palindrome = (str) => {
  let strippedStr = str.replace(/[\W_]/g, '').toLowerCase();
  return strippedStr === [...strippedStr].reverse().join``;
}

I like the use of the spread operator [...strippedStr] instead of split(). Iā€™ve never seen join`` before. I think this is called a Tagged Template. In this case, I think, the tag is join() and itā€™s being passed an empty string (''). If someone knows more about this, please share as Iā€™m not sure if this is whatā€™s happening. Is this much better than join('')?

Anyone else finish this and want to share something interesting about their solution?

:sunny:

Hereā€™s my explanation and code for the next JavaScript project:

Roman Numeral Converter

I started with a bunch of if and else if statements, using an object for the roman numerals:

const convertToRoman = num => {
    const romanNumerals = {
            1: "I",
            4: "IV",
            5: "V",
            9: "IX",
           10: "X",
           40: "XL",
           50: "L",
           90: "XC",
          100: "C",
          400: "CD",
          500: "D",
          900: "CM",
         1000: "M"
        };

    let result = "";

    if (num > 1 && num < 4) {
        result += romanNumerals[1] + convertToRoman(num - 1);
    }

    else if (num > 5 && num < 9) {
        result += romanNumerals[5] + convertToRoman(num - 5);
    }

    else if (num > 10 && num < 40) {
        result += romanNumerals[10] + convertToRoman(num - 10);
    }

    else if (num > 40 && num < 50) {
        result += romanNumerals[40] + convertToRoman(num - 40);
    }

    else if (num > 50 && num < 90) {
        result += romanNumerals[50] + convertToRoman(num - 50);
    }

    else if (num > 90 && num < 100) {
        result += romanNumerals[90] + convertToRoman(num - 90);
    }

    else if (num > 100 && num < 400) {
        result += romanNumerals[100] + convertToRoman(num - 100);
    }

    else if (num > 400 && num < 500) {
        result += romanNumerals[400] + convertToRoman(num - 400);
    }

    else if (num > 500 && num < 900) {
        result += romanNumerals[500] + convertToRoman(num - 500);
    }

    else if (num > 900 && num < 1000) {
        result += romanNumerals[900] + convertToRoman(num - 900);
    }

    else if (num > 1000) {
        result += romanNumerals[1000] + convertToRoman(num - 1000);
    }

    else {
        result = romanNumerals[num];
    }

    return result;

}

Even though that works, I noticed there was a lot of repeating code. However, I wanted to finish the other projects before refactoring. Once I finished the projects, I revisited this code and refactored into the following:

const convertToRoman = num => {
    const romanNumerals = {
            1: "I",
            4: "IV",
            5: "V",
            9: "IX",
           10: "X",
           40: "XL",
           50: "L",
           90: "XC",
          100: "C",
          400: "CD",
          500: "D",
          900: "CM",
         1000: "M"
        };

    let dif = 0;

    if (num <= 0) return;

    if (romanNumerals[num] !== undefined) {
      return romanNumerals[num];
    }
    else {
      while (romanNumerals[num] === undefined) {
        num--;
        dif++;
      }
    }

    return romanNumerals[num] + convertToRoman(dif);
}

This is better, but Iā€™m sure there are better ways to solve this. In looking at the fCC Guide for Roman Numeral Converter, the basic solution shows a simpler, more straightforward way to solve this (updated with ES6 syntax):

const convertToRoman = num => {

  const decimalValue = [ 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ];
  const romanNumeral = [ 'M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I' ];

  let romanized = '';

  romanNumeral.map((numeral, index) => {
    while (decimalValue[index] <= num) {
      romanized += romanNumeral[index];
      num -= decimalValue[index];
    }
  });

  return romanized;
}

The other two solutions in the guide seem more complicated than they have to be. However, maybe there are performance gains from using those methods, I donā€™t know.

There are some interesting ways to solve this problem on the Convert a number into a Roman Numeral in javaScript Stack Overflow question. I found the following solution listed on that page to be interesting because it uses recursion:

function convertToRoman(num) {
    const decimals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
    const roman = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];

    for (let i = 0; i < decimals.length; i++) {
        if(num < 1)
            return "";       

        if(num >= decimals[i]) {
            return roman[i] + convertToRoman(num - decimals[i]);        
        }
    }
}

Iā€™m not sure if this solution is efficient or if it uses best practices, but it works.

The following solution from felixvolny.com also uses recursion, but uses the JavaScript Map Object instead of an object or arrays:

const map = new Map();
map.set('M', 1000);
map.set('CM', 900);
map.set('D', 500);
map.set('CD', 400);
map.set('C', 100);
map.set('XC', 90);
map.set('L', 50);
map.set('XL', 40);
map.set('X', 10);
map.set('IX', 9);
map.set('V', 5);
map.set('IV', 4);
map.set('I', 1);

const convertToRoman = (number) => {
  if (number === 0) {
    return '';
  }

  for (const [roman, integer] of map.entries()) {
    if (number >= integer) {
      return roman + convertToRoman(number - integer);
    }
  }
};

Read through the post at felixvolny.com for a great explanation of the code. Felix has some interesting solutions for other fCC algorithms as well.

I found a solution on selftaughtjs.com. It uses a little math, but the num%decimal[i] < num can be exchanged for decimalValue[index] <= num, which makes it identical to the basic solution in the fCC Guide. I like the detailed explanation. It describes what Roman Numerals are, how the solution was created, and how it works.

Thereā€™s also an exaplanation of how to convert from Roman Numerals to Arabic Numerals on the selftaughtjs.com page.

Maria Campbell has a great write up of the problem and solution as well, if one wants another explanation.

As mentoined on the selftaughtjs.com page, this Roman Number converter by Bert McLees on jsfiddle.net goes far deeper than the fCC requirements. Itā€™s well-documented in case oneā€™s curious how to do something like this.

Thoughts and criticisms welcome. :sunny:

1 Like

This is my solution and some other solutions for the third JavaScript project:

Caesars Cipher

Hereā€™s my solution. Itā€™s not that great, but it works.

const rot13 = str => {
  
  return [...str].map(char => {
    let charCode = char.charCodeAt();
    let decode = 0;

    if (charCode >= 65 && charCode <= 90) {
      decode = charCode - 13;
      if (decode < 65) decode = 90 - (13 - (charCode - 64));
    }
    else {
      return char;
    }

    return String.fromCharCode(decode);
  }).join('');
}

The basic solution in the fCC Guide for Caesarā€™s Cipher helped me create this solution:

const rot13 = str => {
  
  return [...str].map(char => {
    let charCode = char.charCodeAt();

    if (charCode < 65 || charCode > 90) {
      return char;
    }

    else if (charCode < 78) {
      return String.fromCharCode(charCode + 13);
    }

    else {
      return String.fromCharCode(charCode - 13);
    }
  }).join('');
}

Itā€™s a little cleaner, only having charCode + 13 and charCode - 13 instead of the much more cumbersome decode = 90 - (13 - (charCode - 64)). The intermediate and advanced solution lead me to:

const rot13 = str => [...str].map(char => char.match(/[A-Z]/) ? String.fromCharCode(char.charCodeAt() % 26 + 65) : char).join('');

This is a nice one-line solution and the formula becomes a little more complicated. It enables me to only use one formula instead of multiple, like the above solution. It also uses a regular expression, which I hadnā€™t thought of using (but should have!). Then, thinking about the replace() string method shown in the advanced solution, I got this:

const rot13 = str => str.replace(/[A-Z]/g, char => String.fromCharCode(char.charCodeAt() % 26 + 65));
1 Like

This is my solution for the fourth JavaScript project along with some commentary and other solutions:

Telephone Number Validator

This was my first attempt. Itā€™s a long and complicated regular expression. It passes all of the tests, but it doesnā€™t respond correctly for every possible input. For example, 5555555555 5555555555 ā€“ two sequences of 10 numbers returns true instead of false:

function telephoneCheck(str) {
  let regex = /^\d{10}(?!\d)|(^1(-|\s)\d{3}|^\(\d{3}\)|}|^1(-|\s|)\(\d{3}\)|^\d{3})(\s|-|)\d{3}(-|\s)\d{4}/;
  return regex.test(str);
}

What I didnā€™t use in my solution was the ? which matches either zero or one times. This wouldā€™ve helped the situations where sometimes thereā€™s a space and sometimes thereā€™s not, but itā€™s still valid. The basic solution in the fCC Guide for Telephone Number Validator uses the ? successfully. The guide has great explanations for this regular expression:

function telephoneCheck(str) {
   var regex = /^(1\s?)?(\(\d{3}\)|\d{3})[\s\-]?\d{3}[\s\-]?\d{4}$/;
   return regex.test(str);
}

The intermediate solution in the fCC Guide doesnā€™t pass all of the tests because it returns true for 555-5555 and 5555555. However, it is more comprehensive and returns true for phone numbers like 555.555.5555 and (555)555.5555 using dots instead of dashes or spaces. Instead of pasting it here, I added checking for periods and +1 to the basic solution to make that solution more comprehensive:

function telephoneCheck(str) {
   var regex = /^(\+?1\s?)?(\(\d{3}\)|\d{3})[\s-.]?\d{3}[\s-.]?\d{4}$/;
   return regex.test(str);
}

This solution on Stack Overflow (Comprehensive Regex for Phone Number Validation) is similar to the intermediate solution in the guide and matches every combination of U.S. phone number. It also fails the fCC tests for 555-5555 and 5555555 by returning true instead of false:

function telephoneCheck(str) {
   var regex = /^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/;
   return regex.test(str);
}

Hereā€™s the last JavaScript project for me! :sunny:

Cash Register

The difficult part for me was figuring out the best unit of change to return when there were multiple ways to give the change. I created a cidCounts array which contained the unit name, value of units in drawer, count of units in drawer, and value of the unit.

const checkCashRegister = (price, cash, cid) => {
  const UNITS = {
    "PENNY": .01,
    "NICKEL": .05,
    "DIME": .1,
    "QUARTER": .25,
    "ONE": 1,
    "FIVE": 5,
    "TEN": 10,
    "TWENTY": 20,
    "ONE HUNDRED": 100
  }

  let cidCounts = cid.map(item => [item[0], item[1], Number((item[1] / UNITS[item[0]]).toFixed(2)), UNITS[item[0]]]);

  let changeOwed = cash - price;

  let change = [];

  while (changeOwed !== 0) {

    let filteredItems = [];
      
    for (let key in UNITS) {
      if (changeOwed >= UNITS[key]) {
        for (let item of cidCounts) {
          if (item[0] === key && item[2] !== 0) {
            filteredItems.push(item);
          }
        }
      }
    }

    filteredItems.sort((a, b) => a - b);

    let filteredTotal = Number(filteredItems.map(unit => unit[1]).reduce((acc, cur) => acc + cur).toFixed(2));

    if (changeOwed > filteredTotal) {
      return {status: "INSUFFICIENT_FUNDS", change: []};
    }
    
    else if (changeOwed === filteredTotal){
      return {status: "CLOSED", change: cid};
    }

    else {
      let unit = filteredItems[0][0];
      let value = filteredItems[0][3];

      if (change.filter(item => item[0] === unit).length !== 0) {
        for (let item of change) {
          if (item[0] === unit) {
            item[1] += value;
            filteredItems[0][2]--;
            filteredItems[0][1] -= value;
            changeOwed = Number((changeOwed - value).toFixed(2));
          }
        }
      }
      else {
        change.push([unit, value]);
        filteredItems[0][2]--;
        filteredItems[0][1] -= value;
        changeOwed = Number((changeOwed - value).toFixed(2));
      }
    }
  }
  return {status: "OPEN", change: change};
}

Iā€™m curious to learn how others solved this and/or ways I can improve this code. I feel like this can be done in a better way than the way I did and better than itā€™s done in the fCC Guide for Cash Register.

I will not be facilitating another cohort, but if anyone wants to try to facilitate one, please use anything from what Iā€™ve written in the forum or elsewhere as needed. Thanks for everyoneā€™s participation and for the VERY helpful feedback!!

1 Like

Good job guys! Sorry, Iā€™ve been on vacation the last couple of weeks. I still have 3 of the final projects left. Hopefully Iā€™ll finish this week and get that cert!