Snail Array Challenge Solution JavaScript

Day 5 of 365 days of coding!

Today we are borrowing a challenge from Codewars!

Disclaimer: This is not my challenge the original challenge is linked about. Also, there are MANY ways to solve this problem. These are a few answers that I wrote or find clever with explanations of why/how they work

TLDR: explanation of best solution at the bottom of the post and actual solutions at the bottom of each section

The Problem

Create a function that accepts and array. Given an n x n array, return the array elements arranged from outermost elements to the middle element, traveling clockwise.

Examples:

        snail( [[1,2,3], [4,5,6],[7,8,9]]) // [1,2,3,6,9,8,7,4,5] 
        snail([[1,2,3], [8,9,4], [7,6,5]]) // [1,2,3,4,5,6,7,8,9]
        snail([[1,2,3,1], [4,5,6,4], [7,8,9,7], [7,8,9,7]]) // [1,2,3,1,4,7,7,9,8,7,7,4,5,6,8,9]

The image below may help. You can also go to the Codewars page for more information and to test out your solution

snail.png

Solutions

So lets break down some possible solutions

  • possibility 1

    • create a variable for the final array

    • loop through the parent array - while array still has items in it

      • get the first row (first array in the array)

      • get the items at the end of each array (right side)

      • get the bottom row from end to front (bottom row reversed)

      • get the items at the beginning of the arrays (left side)

  • possibility 2

    • create a variable for the final array

    • loop through the parent array - while array still has items in it

      • get the fist row

      • get the last item in each array

      • reverse the parent array and each array in the parent array

Solution 1 - Readability and Performance

First we need to create out function that accepts an array

const snail = (arr) => {
  //create a variable for the final array
  //loop through the parent array - while array still has items in it
    //get the first row (first array in the array)
    //get the items at the end of each array (right side) 
    //get the bottom row from end to front (bottom row reversed)
    //get the items at the beginning of the arrays (left side)
}

We have to create variable to push everything into to get our final array. We will instantiate this as an empty array that everything will get added to and if there is nothing to add it to we will return the [] at the end as expected

const snail = (arr) => {
  let finalArray = []
  //loop through the parent array - while array still has items in it
    //get the first row (first array in the array)
    //get the items at the end of each array (right side) 
    //get the bottom row from end to front (bottom row reversed)
    //get the items at the beginning of the arrays (left side)
}

Now we need to add a while loop. If you are not familiar with them check out this MDN page. We need to do a while loop here because we don’t know how many times the loop is going to have to go through to get the final answer. We are going to make the loop while array has a length as we will be removing items from each array as we loop. In the end the array will have nothing left in it so the length will be 0 and that is when we will end to loop execution.

const snail = (arr) => {
  let finalArray = []
  while (arr.length){
    //get the first row (first array in the array)
    //get the items at the end of each array (right side) 
    //get the bottom row from end to front (bottom row reversed)
    //get the items at the beginning of the arrays (left side)
  }
}

We want to get the first array in the array of arrays (the first row) if you don’t know how .shift() .push(), or the spread operator works check out this MDN page but basically it takes the first item in an array.

const snail = (arr) => {
  let finalArray = []
  while (arr.length){
    finalArray.push(...arr.shift())
    //get the items at the end of each array (right side) 
    //get the bottom row from end to front (bottom row reversed)
    //get the items at the beginning of the arrays (left side)
  }
}

We need to get all the items at the end of each array (the right side) if you are unfamiliar with for loops or .pop() check out the links on each one before continuing.

const snail = (arr) => {
  let finalArray = []
  while (arr.length){
    finalArray.push(...array.shift())
    for (var i = 0; i < arr.length; i++) {
        finalArray.push(arr[i].pop());
    }
    //get the bottom row from end to front (bottom row reversed)
    //get the items at the beginning of the arrays (left side)
  }
}

now we need to get the last array and reverse it (bottom line) if you are unfamiliar with .reverse() check out this MDN page before continuing. you will notice that I am giving it an empty array just in case there is no last array or nothing is there the .reverse will error if it doesn’t have at least an empty array so we are giving it an empty array if array doesn’t have something to pop.

const snail = (array) =>{
  let finalArray = []
  while(array.length){
    finalArray.push(...array.shift())
    for (var i = 0; i < array.length; i++){
      finalArray.push(array[i].pop())
    }
    finalArray.push(...(array.pop() || []).reverse())
    //get the items at the beginning of the arrays (left side)
  }
}

All we have left is to get the left side so we need to get all of the first items from each array. You will notice that i is going to be the length of the array -1 because we don’t want to grab the first array. we will grab that in the next loop so we only want the first numbers from each array before the first one.

const snail = (array) =>{
  let finalArray = []
  while(array.length){
    finalArray.push(...array.shift())
    for (var i = 0; i < array.length; i++){
      finalArray.push(array[i].pop())
    }
    finalArray.push(...(array.pop() || []).reverse())
    for (var i = array.length -1; i >= 0; i--){
      finalArray.push(array[i].shift())
    }
  }
}

Last but not least, we return that finalArray that we have been building

const snail = (array) =>{
  let finalArray = []
  while(array.length){
    finalArray.push(...array.shift())
    for (var i = 0; i < array.length; i++){
      finalArray.push(array[i].pop())
    }
    finalArray.push(...(array.pop() || []).reverse())
    for (var i = array.length -1; i >= 0; i--){
      finalArray.push(array[i].shift())
    }
  }
  return finalArray
}

Solution 2 - Clever and Less Lines of Code

This solution is one everyone loves on Codewars it is less performant and I don’t like the readability of it but it is less lines of code and very clever so I thought I would share it with you.

The first few lines are the same as the first solution

const snail = (arr) => {
  var finalArray = [];
  while (arr.length) {
    finalArray.push(...arr.shift());
    //get the last item in each array
    //reverse the parent array and each array in the parent array
  }
}

The next part is very similar to the first solution and you can actually switch our the first for loop for this but we are going to use .map() to get the last number from each array (row) and push it into the finalArray

const snail = (arr) => {
  var finalArray = [];
  while (arr.length) {
    finalArray.push(...arr.shift());
    arr.map(row => finalArray.push(row.pop()))
    //reverse the parent array and each array in the parent array
  }
}

This is where it gets really interesting. Instead of getting the bottom row reversed now we are going to reverse the whole array and each item in the arrays within the parent array and do all the same logic. This will flip everything so instead of getting the top row we are getting the bottom and instead of getting the right side we are getting the left. Then the loop continues

const snail = (arr) => {
  var finalArray = [];
  while (arr.length) {
    finalArray.push(...arr.shift());
    arr.map(row => finalArray.push(row.pop()))
    arr.reverse().map(row => row.reverse());
  }
}

At the end we return our finalArray and TA DA! you have your solution

const snail = (arr) => {
  var finalArray = [];
  while (arr.length) {
    finalArray.push(...arr.shift());
    arr.map(row => finalArray.push(row.pop()))
    arr.reverse().map(row => row.reverse());
  }
  return finalArray
}

pretty cool huh?

Conclusion

The second solution is pretty clever and has less lines but it is harder to read and it is not as performant. below is the jsbench performance results using the examples above for anyone who is interested.

jsbench.PNG

I hope you had fun with this one! Please leave your solutions that you came up with in the comments section. If you have any challenge you would like to see done also leave that in the comments below you may see it come up! If you would like to get the challenge emailed to you every day in morning and a notification when the solution is posted subscribe below

Previous
Previous

Day 6 Challenge

Next
Next

Day 5 Challenge