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

Here are my first five solutions for the Intermediate Algorithm Scripting section and some commentary about my solutions and solutions I found in the fCC Guide:

Sum All Numbers in a Range

My first solution was the following, using recursion:

function sumAll(arr) {
  // Create new array to use in function. Sort array from highest to lowest.
  let newArr = arr.sort((a, b) => b - a);

  // If the difference between both numbers is zero, then return the first number in the array.
  if (newArr[0] - newArr[1] === 0) return newArr[0];

  // return the first number in the array plus the function again, but this time with the first number minus one.
  return newArr[0] + sumAll([newArr[0] - 1, newArr[1]]);
}

The fCC Guide entry for the Sum All Numbers in a Range challenge shows a solution that uses a for-loop, a solution using something called the Arithetic Progression summing formula, and the following solution that uses the spread operator (...) along with a for-loop, Math.min(), and Math.max():

function sumAll(arr) {
    var sum = 0;
    for (var i = Math.min(...arr); i <= Math.max(...arr); i++){
        sum += i;
    }
  return sum;
}

I like this final solution because it seems self-contained and not too complicated. The main part of this challenge is using the first and last numbers, and this solution does that in an elegant way. I think my solution over-complicates this challenge.

Diff Two Arrays

Here’s my solution, using filter(), arrow functions, the spread operator, and indexOf():

function diffArray(arr1, arr2) {
  let newArr = [];
  
  newArr.push(...arr2.filter(item => arr1.indexOf(item) === -1));
  newArr.push(...arr1.filter(item => arr2.indexOf(item) === -1));
  
  return newArr;
}

The fCC Guide entry for Diff Two Arrays has some interesting solutions that use includes(). The solution I like best first concatenates both arrays and then filters the concatenated array to only include items that are not in either array:

function diffArray(arr1, arr2) {
      return arr1.concat(arr2).filter(item => !arr1.includes(item) || !arr2.includes(item));
}

I moved everything into one line here, but if you want to see it broken out into multiple lines, click on the guide link above.

Seek and Destroy

My first solution used filter(), slice, and indexOf():

function destroyer(arr) {  
  return arr.filter(item => [...arguments].slice(1).indexOf(item) === -1);
}

However, after reviewing the above solutions in the guide, I tried includes() instead of indexOf() and I think it’s a little cleaner:

function destroyer(arr) {  
  return arr.filter(item => ![...arguments].slice(1).includes(item));
}

The fCC Guide entry for Seek and Destroy shows a solution using nested for-loops and one that’s close to my solution that uses includes(), but uses Array.from(arguments) which does the same thing as [...arguments].

Wherefore Art Thou

I think I cheated a little on this one. My solution doesn’t work for all possible test cases, but it passes all of the tests given for the challenge. I used Object.keys and filter():

function whatIsInAName(collection, source) {

  var arr = [];
  const keys = Object.keys(source);

  arr.push(...collection.filter(item => item[keys[0]] === source[keys[0]] && item[keys[1]] === source[keys[1]]));

  return arr;
}

If, for example, the source for the second to last test case is { "apple": 1, "bat": 2, "cookie": 3 } instead of { "apple": 1, "bat": 2 }, my solution will return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie":2 }] even though it should return an empty array since none of the objects match the source. This is because I’m only checking the first two keys and ignoring any more after that. Since it passed the tests and I was in a hurry (thinking the deadline for this section was June 30, 2018), I moved on.

The solutions in the fCC Guide for Wherefore Art Thou work correctly and as expected for all possible test cases using hasOwnProperty(). This solution in the guide that spoke to me the most:

function whatIsInAName(collection, source) {
 
  var srcKeys = Object.keys(source);

  return collection.filter(function (obj) {
    return srcKeys.every(function (key) {
      return obj.hasOwnProperty(key) && obj[key] === source[key];
    });
  });
}

With that, I was able to come up with the following similar solution using more ES6 syntax:

function whatIsInAName(collection, source) {

  const keys = Object.keys(source);

  return collection.filter(collectionItem => keys.every(key => collectionItem.hasOwnProperty(key) && collectionItem[key] === source[key]));

}

I hope I remember to use this filter() - every() combination in the future!

Spinal Tap Case

For this one, I had two solutions which basically combined split() and join() in various ways with regular expressions. Here’s one of them:

function spinalCase(str) {
  str.split(/[ _]/g).map(item => item.split(/(?=[A-Z])/g)).join('-').toLowerCase().replace(/[,]/g, '-');
}

Interestingly, the solutions in the fCC Guide for Spinal Tap Case don’t seem to pass all of the tests anymore.

@Velenir and the fCC Forum to the rescue. :smile: @Velenir’s solution passes all of the tests and uses a nice regular expression to do it in one line:

function spinalCase(str) {
  return str.split(/[-\s_]|\B(?=[A-Z])/).join('-').toLowerCase();
}

I’ll have to come back to this one when I have some time to truly understand how that regular expression is working. If anyone understands, please explain! Thanks.

Anyone come up with any other interesting ways to solve these challenges? :sunny:

1 Like