# CoDEVIANT #17 (10/3/20) — Pick T̶h̶r̶e̶e̶ Two, M’Lord

Problem:

Let’s write a function that takes two non-empty arrays of integers. This function will find the pair of numbers (one from each array) whose absolute difference is the closest to zero.

Then the function returns the values from each array in a new array like so:

`[valueFromArray1, valueFromArray2]`

In other words:

So I’m super jazzed to say that thanks to the thing I learned about pointers in the last coDEVIANT article, I was able to apply similar logic and find a solution.

Et voila:

`function smallestDifference(arrayOne, arrayTwo) { let unoCounter = 0 let dosCounter = 0 let computedValue = null   for(let i = 0; i < arrayOne.length; i ++) {  arrayTwo.forEach((el, index) => {   let value = Math.abs(el - arrayOne[i])   if(computedValue === null || value < computedValue) {    computedValue = value    unoCounter = i    dosCounter = index   }  }) } return [ arrayOne[unoCounter], arrayTwo[dosCounter] ]}`

So let’s get the easy stuff down first.

Anyways…

We create two variables that equal 0 to start: unoCounter and dosCounter. Then we create a variable called computedValue which equals null.

`let unoCounter = 0let dosCounter = 0let computedValue = null`

Next we are going to create a classic for-loop that iterates through the arrayOne argument that is passed into the function. It will have i start at 0, keep going through the length of arrayOne and will augment i by one each round.

`for(let i = 0; i < arrayOne.length; i++) { .....}`

Next we’re going to use the forEach array-method inside of this for-loop on the arrayTwo argument passed into the function.

`for(let i = 0; i < arrayOne.length; i++) {   arrayTwo.forEach(el => {      ...   })}`

Inside the forEach method, we:
- Create a new variable called value which will equal the absolute value of el minus whatever value is represented by arrayOne[i] at that moment.

`for(let i = 0; i < arrayOne.length; i++) {   arrayTwo.forEach(el => {      let value = Math.abs(el - arrayOne[i])   })}`

Right under where we established the value variable, we create an if-statement saying that if computedValue equals null or if value is less than computedValue, we:

• set computedValue to equal whatever value is
• set unoCounter to equal whatever i from the classic for-loop is
• set dosCounter to equal index from the use of the forEach-array method ((When you use forEach the first argument, el, in our case, is the value of the array-element. The second argument, index, in our case, is the array-index where the value is located))
`for(let i = 0; i < arrayOne.length; i++) {   arrayTwo.forEach(el => {      let value = Math.abs(el - arrayOne[i])      if(computedValue === null || value < computedValue) {         computedValue = value         unoCounter = i         dosCounter = index      }   })}`

Then we return an array with the first element being whatever value is at arrayOne[unoCounter] and the second element being whatever value is at arrayTwo[dosCounter].

`return [ arrayOne[unoCounter], arrayTwo[dosCounter] ]`

Full solution again:

`function smallestDifference(arrayOne, arrayTwo) { let unoCounter = 0 let dosCounter = 0 let computedValue = null   for(let i = 0; i < arrayOne.length; i ++) {  arrayTwo.forEach((el, index) => {   let value = Math.abs(el - arrayOne[i])   if(computedValue === null || value < computedValue) {    computedValue = value    unoCounter = i    dosCounter = index   }  }) } return [ arrayOne[unoCounter], arrayTwo[dosCounter] ]}`

I plugged my solution in, ran it, and all the test-cases passed.

How did the super-nerds do it?…

`function smallestDifference(arrayOne, arrayTwo) { arrayOne.sort((a,b) => a-b) arrayTwo.sort((a,b) => a-b) let idxOne = 0 let idxTwo = 0 let smallest = Infinity let current = Infinity let smallestPair = [] while(idxOne < arrayOne.length && idxTwo < arrayTwo.length){  let firstNum = arrayOne[idxOne]  let secondNum = arrayTwo[idxTwo]    if(firstNum < secondNum){    current = secondNum - firstNum    idxOne++  } else if(secondNum < firstNum){    current = firstNum - secondNum    idxTwo++  } else {    return [firstNum, secondNum]  }  if(smallest > current) {    smallest = current    smallestPair = [firstNum, secondNum]  } }  return smallestPair}`

So what’s interesting about this solution is that it only uses one loop, a while-loop, to drive the calculation. My solution used two for-loops (one was a classic for-loop and the other is implied by the use of the forEach array-method). This is a better, more lightweight (computationally speaking) solution because, unlike mine, this does NOT compare every single possible combination in order to find the smallest pair.

And now it is…

First we sort the arrays that are passed in as arguments. We want to have these arrays in ascending order.

`arrayOne.sort((a,b)=> a - b)arrayTwo.sort((a,b)=> a - b)`

Then we create some variables to help us keep track of things:

• idxOne: the counter for arrayOne; set to 0
• idxTwo: the counter for arrayTwo; set to 0
• smallest: to keep track of the smallest difference; initially set to Infinity so that no matter what the first difference between values is, it is smaller.
• current: to keep track of the current difference between the two values presently at play; initially set to Infinity as well
• smallestPair: an empty array that will hold the appropriate value from each of the arrays; this is the answer we will return in our function
`let idxOne = 0let idxTwo = 0let smallest = Infinitylet current = Infinitylet smallestPair = []`

Now we create a while-loop, which will remain active as long as idxOne is smaller than the length of arrayOne AND as long as idxTwo is smaller than the length of arrayTwo. The way we will be setting up our logic in this while-loop is such that if either of the pointers exceed the length of their respective arrays, because we’ve sorted the arrays in ascending order, we will have our answer to put into smallestPair which we can then return.

`while(idxOne < arrayOne.length && idxTwo < arrayTwo.length) {   ...}`

Now inside the while-loop, we’re going to set up two variables:

• firstNum: the value at arrayOne at the position indicated by idxOne
• secondNum: the value at arrayTwo at the position indicated by idxTwo
`while(idxOne < arrayOne.length && idxTwo < arrayTwo.length) {   let firstNum = arrayOne[idxOne]   let secondNum = arrayTwo[idxTwo]}`

Next we set up an if-else-statement with three levels. It will compare the difference between firstNum and secondNum (or vice-versa) depending on which one is larger. If firstNum is larger, then idxOne gets increased by one. If secondNum is larger, then idxTwo gets increased by one. If they are the same, then that means the difference is 0, we can pack our bags, return whatever firstNum and secondNum are immediately and call it a day.

Immediately under the if-else statement, we create another if-statement stating that if the value of our smallest variable is larger than current, we set smallest to equal whatever value current presently has. smallestPair is also set to equal an array containing firstNum as its first element and secondNum as its second element.

`while(idxOne < arrayOne.length && idxTwo < arrayTwo.length) {   let firstNum = arrayOne[idxOne]   let secondNum = arrayTwo[idxTwo]   if(firstNum < secondNum) {     current = secondNum - firstNum     idxOne++   } else if(secondNum < firstNum){     current = firstNum - secondNum     idxTwo++   } else {     return [firstNum, secondNum]   }   if(smallest > current) {     smallest = current     smallestPair = [firstNum, secondNum]   }}`

So before we go any further, let’s break logically what’s happening here.
Let’s say we have our sorted arrays:

• arrayOne = [-1, 3, 5, 10, 20, 28]
• arrayTwo = [15, 17, 26, 134, 135]

At the start of the first run of the while-loop, firstNum is going to be -1 and secondNum is going to be 15.

In our if-else statement, we’re going to playing with the first if-block because our situation is such that firstNum is less than secondNum. In this case current equals 15 minus 1, which, according to my remedial math skills, equals 14.

We stroll on down to the subsequent if-statement and compare our current (at this point 14) to smallest (at this point Infinity). Plot twist (j/k) 14 is smaller than Infinity, so smallest becomes 14. smallestPair also becomes [-1, 15].

At this point we have reached the end of a cycle of our while-loop that our if-else statement and if statement are inside of. The while loop doesn’t stop until either idxOne or idxTwo are larger than the length of their respective arrays, however. So we repeat this again, except this time while idxTwo is still 0, idxOne is 1. The image below details how the while-loop (with its inner if-else statement and if-statement) churn out the answer for us. This is basically how our algorithm works with the while loop requiring that idxOne and idxTwo never get larger than the lengths of their arrays.

When firstNum was smaller than secondNum, we increased idxOne to see if we could get a value that would yield a smaller difference, and vice-versa. This is the driving calculation behind this better answer: an answer that doesn’t need to figure out every single possible calculation and then give us a report. This sucker only needed 6 turns to get us the pair with the smallest difference.

`function smallestDifference(arrayOne, arrayTwo) { arrayOne.sort((a,b) => a-b) arrayTwo.sort((a,b) => a-b)let idxOne = 0 let idxTwo = 0 let smallest = Infinity let current = Infinity let smallestPair = []while(idxOne < arrayOne.length && idxTwo < arrayTwo.length){  let firstNum = arrayOne[idxOne]  let secondNum = arrayTwo[idxTwo]    if(firstNum < secondNum){    current = secondNum - firstNum    idxOne++  } else if(secondNum < firstNum){    current = firstNum - secondNum    idxTwo++  } else {    return [firstNum, secondNum]  }if(smallest > current) {    smallest = current    smallestPair = [firstNum, secondNum]  } }  return smallestPair}`

I really liked this problem because I felt really good about being able to solve it the first time by myself. The better solution was great because it introduced me the Infinite JavaScript concept and gave me another way to leverage pointers with arrays. All in all, it was a good day.

Thanks so much for checking out this edition of coDEVIANT. If you have any questions, comments, or concerns drop a comment. If this was useful or you enjoyed my attempt at making this guide humorous and accessible, give me a clap, or better yet, a follow!

Ok, nerds…

--

--

is a web developer, opera singer, actor, and lover of cats. (adrian-rosales.tech)