Discussion, Questions, and Resources for Part 2 (JavaScript Basic Algorithms, Object-Oriented, and Functional Programming - April 2018 Cohort)

@nvrqt03 I was able to pass the exercise using splice().

function filteredArray(arr, elem) {
    let newArr = [];
    // change code below this line
    
   for (let i = 0; i < arr.length; i++) {
        if (arr[i].indexOf(elem) !== -1) {
        arr.splice(i, 1);
        i--; // account for array modification
      }  
    }
      
    newArr = arr;
    // change code above this line
    return newArr;
  }
  
  // change code here to test different cases:
  console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
2 Likes

great solutions guys! glad to see someone got splice to work. basically I was trying to say that if the element does NOT exist in the array -

if (arr[i ].indexOf(elem) !== -1 

then to splice them from the array. they will make their own new array of uh… undesirables? then we will push what’s left to the newArr and return that. however I noticed @smsguy927 you didn’t push to the new array, and I’m not sure how i- - ; works in this situation.

sorry for the late reply, I code early in the morning. usually I can get some coding in after work as well, or respond during work. It was busy yesterday though.

splice() modifies the array it is called on and it shifts the indexes of the array when no elements are replaced after splicing. i-- accounts for this modification and ensures that arr[i] will point to the next element in the array in the next iteration. Then I assign what’s left in the initial array to the result array.

if (arr[i].indexOf(elem) !== -1)

@nvrqt03 This will return true if elem is in arr[i].

indexOf(elem) either returns the index of the item in the array that matches elem or returns -1 if there is no match.

In the above, you’re returning true if arr[i].indexOf(elem) does not equal !== -1, i.e. return true if arr[i].indexOf(elem) returns an index of a matched item in the array, or return true if it returns anything other than -1.

The following returns true if elem is NOT in arr[i]:

if (arr[i].indexOf(elem) === -1)

That’s how I’m reading this. Let me know if I’m wrong.

1 Like

if (arr[i].indexOf(elem) === -1)
if that returns true, then the element is not in the current sub-index. that is exactly what we’re looking for. so from here, you can skip all the slicing and splicing and just:
newArr.push(arr[i])

for (let i = 0; i < arr.length; i++) {
if (arr[i].indexOf(elem) === -1) {
newArr.push(arr[i]);
}
}

2 Likes

Here are my solutions for the first three algorithms:

Convert Celsius to Fahrenheit
function convertToF(celsius) {
  return (celsius * (9/5)) + 32;
}
Reverse a String

I came up with the following, which splits the string into an array of letters and then adds the letters to a new string using the map() function.

function reverseString(str) {
  let newStr = "";
  return str.split('').map(letter => newStr = letter + newStr)[newStr.length-1];
}

However, after looking through the freeCodeCamp Algorithm Challenge Guide: Reverse a String topic, I realized that I overcomplicated this and should’ve looked to built-in functions instead:

function reverseString(str) {
  return str.split('').reverse().join('');
}
Factorialize a Number

I started with the following, using a for loop to loop through the range between num and one and then multiply the counter by the current result:

function factorialize(num) {
  let result = 1;
  for (let numIndex=num; numIndex > 0; numIndex--) {
    result *= numIndex;
  }
  return result;
}

However, after looking at the freeCodeCamp Algorithm Challenge Guide: Factorialize A Number topic, and watching the video on recursion listed in the guide and this part of another video on recursion, I came up with this, which is more difficult to understand, but cleaner overall:

function factorialize(num) {
  if (num === 0) return 1;
  return num * factorialize(num-1);
}

The following is another version shared by @Kagerjay (freeCodeCamp Algorithm Challenge Guide: Factorialize A Number) that I like the best, once I wrap my head around recursion:

function factorialize(num) {
  return num === 0 ? 1 : num * factorialize(num-1);
}

This Recursion and Recursive Functions video does a great job of explaining how the above recursive factorialize function works.

Any thoughts on the above solutions? Did anyone do anything different or find helpful resources to learn more about these? :sunny:

3 Likes

for the first one, converting celsius to fahrenheit, I essentially got the same as you. I only let fahrenheit equal the celsius conversion, and returned fahrenheit.

reversing a string - i got your second solution.

factorialize - slightly different -

```function factorialize(num) {
if (num === 0 || num === 1)
return 1;
for (let i = num - 1; i >= 1; i–) {
num *= i;
}
return num;
}

I’ll definitely check out that recursion video!

Here are a couple others:

find the longest word in a string:

```function findLongestWordLength(str) {
let largestWord = 0;
str = str.split(’ ');
for (let i = 0; i < str.length; i++) {
if (str[i].length > largestWord) {
largestWord = str[i].length;
}
}
return largestWord;
}

return largest numbers in arrays:

```function largestOfFour(arr) {
let largestNumber = [0,0,0,0];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] < 0) {
arr[i].sort(function (a, b) {
return a - b;
});
largestNumber[i] = arr[i][0];
}
if (arr[i][j] > largestNumber[i])
largestNumber[i] = arr[i][j];
}
}
return largestNumber;
}

I’m working on the Confirm the Ending challenge. I think I"m close, but its inconsistent. its finding anything, not just at the end.

function confirmEnding(str, target) {
// “Never give up and good luck will find you.”
// – Falcor
if (str.lastIndexOf(target) > 0) {
return true;
}
else {
return false;
}
}

1 Like

@nvrqt03 Thanks for sharing! Anyone else want to share or have comments on any of the solutions shared so far?

Here are my solutions for the next three algorithms.

Find the Longest Word in a String

For Of Loop
I like this one the best at this point in my understanding of JavaScript because it’s straightforward and there’s no unseen things happening.

function findLongestWordLength(str) {
  let longest = 0;
  let wordsArr = str.split(' ');

  for (let word of wordsArr) {
    if (word.length > longest) {
      longest = word.length;
    }
  }
  return longest;
}

Filter()
This is similar to the For Of Loop, but it uses filter() instead. I’m not sure if there are benefits to doing it this way.

function findLongestWordLength(str) {
  let longest = 0;
    str.split(' ').filter(word => {if (word.length > longest) longest = word.length});
  return longest;
}

In the Javascript Coding Challenge #4: Find Longest Word (Freecodecamp), they mention using the sort() method. In the fCC Guide, they recommend two other ways, one using reduce() and Math.max and the other way is to solve this with recursion.

Return Largest Numbers in Arrays

filter() and map()
My first attempt returned the following:

function largestOfFour(arr) {
  
  let largestArr = [];
  
    // Apply (i.e. map) the following filter to each sub array within the array
    arr.map(function(subArr) {
  
        let largest = 0;

        /*
          Filter the largest number from each sub array
          if the number is greater than the previous largest number 
          OR the number is less than zero and the previous largest number is zero
          then set largest to num
        */
        subArr.filter(num => {if (num > largest || (num < 0 && largest === 0)) largest = num});


        // Push the largest number of the sub array to the largestArr array
        largestArr.push(largest);
    
    });
  
  return largestArr;
}

map() and reduce()
I was able to break it down more, which is close to the example in the Return Largest Numbers in Arrays fCC guide entry and less complicated than my first attempt:

function largestOfFour(arr) {
  
  let largestArr = [];
  
    arr.map(subArr =>
            largestArr.push(subArr.reduce((previous, current) =>
                                          previous > current ? previous : current)));
      
  return largestArr;
}
Confirm the Ending

slice()
This is what I ended up with for my first attempt.

function confirmEnding(str, target) {
  return str.slice(str.length - target.length, str.length) === target;
}

substr()
The Confirm the Ending fCC Guide entry suggests another (better) way to do this using substr(). Again, I need to remember to look for better, more appropriate built-in methods:

function confirmEnding(str, target) {
    return str.substr(-target.length) === target;
}

Hopefully, the more I do this the more likely it’ll be that I’ll pick more appropriate methods for my solutions. What do you all think? Does anyone have solutions that aren’t shown or mentioned above? :sunny:

2 Likes

My solution for Return Largest Numbers in Arrays.

I use map() and ES6 spread operator (the 3 dots! … :smile:)

function largestOfFour(arr) {
  return arr.map(chunk => Math.max(...chunk));

  // arr.map() grabs subarrays (I call it chuck here) and call the Math.max function on it to find the largest number in each subarray. 
}

Hope this helps!

3 Likes

I found a great tool for debugging your JavaScript code. It also offers other languages like Python and Ruby.
Basically, it visualizes every single execution of the code to help you debugging.
Not only debugging, I got tons of help to understand JS functions better and faster while solving the Basic Algorithm Scripting section.

The link :point_down:
http://pythontutor.com/visualize.html#mode=edit

5 Likes

@NariRoh Yes! That is a very elegant solution and it’s backed up by the curriculum in the ES6: Use the Spread Operator to Evaluate Arrays In-Place challenge. :fireworks: Thank you!

Here’s a link showing your solution in action using the pythontutor.com service you recommend above. Thank you for that recommendation!

1 Like

Here are my solutions for the next three algorithms:

Repeat a String Repeat a String

My first attempt looked like the following:

function repeatStringNumTimes(str, num) {
  let returnStr = '';
  
  for (let numCount=0; numCount < num; numCount++) {
    if (num > 0) {
      returnStr += str;
    }
  }
  
  return returnStr;
}

In thinking about it further and attempting to figure out a recursive way to accomplish this, I figured this out:

function repeatStringNumTimes(str, num) {
  return num <= 0 ? "" : str + repeatStringNumTimes(str, num-1);
}

The Repeat a String Repeat a String fCC guide shows a while loop solution, recursive solution, and a solution that uses the repeat() method, which the challenge says not to use. I think the while loop solution is more straightforward and easier to understand than my for loop solution above:

function repeatStringNumTimes(str, num) {
  var accumulatedStr = '';

  while (num > 0) {
    accumulatedStr += str;
    num--;
  }

  return accumulatedStr;
}
Truncate a String

This was what I came up with:

function truncateString(str, num) {
  return str.length > num ? `${str.slice(0, num)}...` : str;
}

Interestingly, I think the Truncate a String fCC guide makes it more complicated than it has to be, at least with the current test cases. For instance, line 5 of the advanced code solution is:

return str.slice(0, num > 3 ? num - 3 : num) + '...';

If one uses the following instead, it’ll still pass all of the tests without the need to use another ternary operator:

return str.slice(0, num) + '...';

The advanced solution then becomes very similar to my solution above, except I use a template literal.

I may submit a suggested change to the guide entry if I get the time and energy.

Finders Keepers

My first attempt looked like this:

function findElement(arr, func) {
    for (let num of arr) {
        if (func(num)) return num;
    }
}

Then, I refactored using filter() to get this:

function findElement(arr, func) {
  return arr.filter(item => func(item) ? item : undefined)[0];
}

That’s not too bad, a little awkward maybe. However, according to the Finders Keepers fCC Guide, there’s a much better way to do this using the filter() method:

function findElement(arr, func) {
  filterArr = arr.filter(func);
  return filterArr[0];
}

Which can be refactored even further to:

function findElement(arr, func) {
  return arr.filter(func)[0];
}

Any suggestions for improvement on the above solutions?

How’s everyone doing so far? I’ve noticed that the algorithms tend to take me longer to work on and figure out, especially if I take into account the research I do after I come up with a working solution in order to make that solution better. Anyone else experiencing this? :sunny:

2 Likes

I got this for Finders Keepers

function findElement(arr, func) {
  return arr.find(func);
}

This was my first pass

function findElement(arr, func) {
  for(let i = 0; i < arr.length; i++){
    if(func(arr[i])){
      return arr[i]
    }
  }
}
1 Like

Thanks @camper!

I usually use ‘Live Programming Mode’ I think it’s better :slight_smile:

Link here: http://pythontutor.com/live.html#mode=edit

Repeat a string
function repeatStringNumTimes(str, num) {
  // repeat after me
 let array1 = "";
 if (num <= 0) {
   return "";
 }
 for (let i = 0; i < num; i++) {
   array1 = array1 + str.slice();
 }
 return array1;
}

repeatStringNumTimes("abc", 3);
Truncate a string

function truncateString(str, num) {
  // Clear out that junk in your trunk
	let newArray = '';
	let dots = '...';
	if (str.length > num) {
		newArray = str.slice(0, num).concat(dots);
	}
	if (str.length <= num) {
    newArray = str;
  }
  return newArray;

}

truncateString("A-tisket a-tasket A green and yellow basket", 8);
Finders keepers
function findElement(arr, func) {
  let num = 0;
  for (let i = 0; i < arr.length; i++) {
    if (func(arr[i]) === true) {
      return num = arr[i];
    }
  }
}

findElement([1, 2, 3, 4], num => num % 2 === 0);
BooWho
function booWho(bool) {
  // What is the new fad diet for ghost developers? The Boolean.
  if (bool === true || bool === false) {
    return true;
  } else { return false;}
  
}

booWho(null);

Honestly I was so happy to get them that I didn’t look much into the final solutions. Glad you guys posted them up! I’ve reached #100daysofcode so I took the weekend off, lol.

1 Like

@nvrqt03 and @alhazen1 thanks for sharing your code! Anyone else come up with different code or have questions/comments about what’s been shared so far?

Here are the next three algorithms I completed:

Boo who

My first attempt was to check if the passed in parameter equals either true or false. If it does, return true, otherwise return false:

function booWho(bool) {
  return bool === true || bool === false;
}

In the Boo Who fCC Guide in hint 2, it suggests using the typeof operator, so I came up with this, which is identical to the solution in the guide:

function booWho(bool) {
  return typeof bool === 'boolean';
}
Title Case a Sentence

For my first attempt, I used split(), map(), toUpperCase(), slice(), toLowerCase(), and join():

function titleCase(str) {
  /* 
   1. str.split(' ') - Split the sentence into individual words to create an array.
   
   2. .map(word => word[0].toUpperCase() - Take the first letter of each word and make it uppercase.
  
   3. word.slice(1).toLowerCase() - Take the remaning letters of the word and make them lower case.
   
   4. word[0].toUpperCase() + word.slice(1).toLowerCase() - Join the first letter with the remaining letters of the word.
   
   5. .join(' ') - Join each word, separated by a space, into one string.
   */
  
  return str.toLowerCase().split(' ').map(word => word[0].toUpperCase() + word.slice(1)).join(' ');
}

After thinking about this more and looking at some more built-in JavaScript methods, I came up with a way to do this using substr():

function titleCase(str) {
  return str.toLowerCase().split(' ').map(word => word[0].toUpperCase() + word.substr(1)).join(' ');
}

Both solutions are relatively similar. The Title Case a Sentence fCC Guide has some other ways to do this that seem more complicated and verbose to me, but maybe they make more sense to others. I do like the regex (i.e. replace()) solution:

function titleCase(str) {
  return str.toLowerCase().replace(/(^|\s)\S/g, (L) => L.toUpperCase());
}

The regex here creates a capture group (^|\s) which looks for either the beginning of the string or a space/tab/line break that’s next to a character that’s not a space/tab/line-break (\S), then returns all matches /g in the string.

Falsy Bouncer

I was able to refactor my first attempts into the following which uses filter():

function bouncer(arr) {
  return arr.filter(item => item);
}

According to the Falsy Bouncer fCC Guide, it’s possible to use the Boolean function within filter() like this:

function bouncer(arr) {
  return arr.filter(Boolean);
}

This is a good reminder that built-in functions can be used within map(), reduce(), and filter() functions, not just functions created at the moment (i.e. anonymous functions).

Thanks everyone for looking over my and other’s code and sharing your own code. I’ve learned a lot from you all so far and I’m really grateful for this forum and the fCC community in general. :sunny:

2 Likes

Good stuff to know. I had never thought about that.

Here are the last three algorithms for this section:

Where Do I Belong

I way overcomplicated this one. My solution involved if/else conditions:

function getIndexToIns(arr, num) {
  let sortedArr = arr.sort((a, b) => a - b);

  if (arr.length === 0) {
      return 0;
  }
  
  else {
  
    for (let item of sortedArr) {
      let itemIndex = sortedArr.indexOf(item);

      if (item >= num) {
        return itemIndex;
      }
      else if (sortedArr[itemIndex + 1] === undefined) {
        return itemIndex + 1;
      }
    }
  }
}

There are a few different ways to solve this challenge. The two I like the best, from the Where Do I Belong fCC Guide are:

function getIndexToIns(arr, num) {
  arr.push(num);
  arr.sort(function(a, b){return a-b});
  return arr.indexOf(num);
}

Of course! Add the number into the array, sort, and then return the position of the number. So simple, yet I didn’t think to do it this way. The following is basically the same, but on one line:

function getIndexToIns(arr, num) {
  return arr.concat(num).sort((a,b) => a-b).indexOf(num);
}
Mutations

I was able to get this down to the following:

function mutation(arr) {
  let word1 = arr[0].toLowerCase();
  let word2Arr = arr[1].toLowerCase().split('');

  return word2Arr.filter(letter => word1.indexOf(letter) === -1).length === 0;
}

This creates a new array of only the letters that aren’t in both words, then returns true if all letters are in both words (i.e. if the length of the new array is zero) and false if not.

Chunky Monkey

I was able to get this:

function chunkArrayInGroups(arr, size) {
  let newArr = [];
  while (arr.length !== 0) {
    newArr.push(arr.splice(0, size));
  }
  return newArr;
}

This solution creates an empty array. Then, runs a while loop until the length of the passed-in array is zero. Each time it runs through the loop, it’ll push a splice of the array between zero and size to the new array. Since splice removes the items from the passed-in array, the next pass through the loop will start with the spliced array with the previous items already removed.

I tried to do this recursively, but couldn’t figure it out. Can anyone share a solution of this challenge being solved recursively?

That’s it for me and the Basic Algorithm Scripting section of the beta curriculum. Where’s everyone else at the halfway mark for this part of the cohort? :sunny:

2 Likes

Here’s my final Mutations

function mutation(arr){
  var source = arr[1].toLowerCase().split('');
  var target = arr[0].toLowerCase();
  
  return source.every(function(el){
    return target.includes(el);
  });
}

This is what I started off with

function mutation(arr) {
  let sample = arr[1].toLowerCase();
   let test = arr[0].toLowerCase();
   for(let char of sample){  // test every case for failure (no match)
    if(test.indexOf(char) === -1){
       return false;
     }
   }
   return true;  //if no cases fail 
 }
2 Likes

Thank you for sharing your solutions! :smiley:

I’m on Object Oriented Programming and Intermediate Algorithm Scripting.