Debugging Return Largest Numbers in Arrays

Debugging Return Largest Numbers in Arrays
0

#1

Tell us what’s happening:
I’m having trouble debugging my code.

Right now I want to iterate through each sub array (x) and every item (i) in each subarray. After I’m done iterating through every “i” for a given value of “x”, I assign the largest number to max[x]. I was able to return the largest item in a single array with a single for loop, but adding in the second loop to iterate through items in a subarray is giving me problems.

I asked the function to return an array consisting of x, i and max, but I’m getting an error saying that i is undefined. I can’t for the life of me figure out why! Can anyone help me understand?

Your code so far


function largestOfFour(arr){
	let max = [0];
	for (let x=0; x<arr.length-1; x++){
		for (let i = 0; i < arr[x].length-1; i++){
		if (arr[x][i]>max[x]){
			max[x] = arr[x][i];
		}
		}
	}	
let a = [x,i,max];
return a;

	}

largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-algorithm-scripting/return-largest-numbers-in-arrays/


#2

I think you may have misunderstood the question, judging by what you’re returning

The only thing you should return is the maximum value found in each subarray

You’re also missing the last subarray when you do this: x < arr.length - 1

Not sure why you’re comparing things to max[someElement] really either.

Perhaps it’d be best to start over with the following idea instead:

  1. start with an empty array to hold the results in
  2. loop over the array to get the subarrays
  3. loop over the subarrays, keeping track of the maximum value found in the subarray so far
  4. push the maximum found in the subarray to the results array

#3

Ah, right. I was thinking “let x increase to arr.length-1” but that does miss the last subarray.

Originally I only tried to return “max” (which is intended to be an array of the maximum values in each subarray)— I only returned x and i for debugging purposes.

When x=0, I iterate through arr[x=0][i] for all items (i) the subarray arr[x]. I compare things to max[someElement] because max[x] starts at 0. If arr[x=0][i=0] is greater than zero, max[x] becomes arr[x][i]. If arr[x=0][i=1] is greater than max[0], max[0] becomes arr[0][1]. Then once the loops complete the first subarray (i.e. when x=0 becomes x=1), the value of max[0] becomes locked, and the function starts determining the value for max[1].

Basically I thought I was doing exactly the steps you listed (expect rather than push max values to an array I used values in my for loop that reference subarrays to add values to the array of max values):

  1. the empty array I have is max = [0]. I tried doing max=[] but then there is no value of max to compare to each value within subarrays.

  2. and 3. I want both of my loops to iterate over the items in each subarray, and I keep track of the maximum value by starting with a “max” (in this case max starts out as [0]) and seeing if the next value in each subarray is greater than this “max” value.

  3. Rather than pushing values to an array. I know that while x=0, my for loop is iterating of the subarray arr[0], so I just set newArray[x] to the highest value in arr[x].

I hope the explanation of my logic wasn’t too complicated. Im still scratching my head here. Thanks for your response


#4

interesting way to do it, though I think a temporary variable makes things a lot cleaner

so with those points aside, what is the value of max[1] at the start of the inner loop? it’s not 0 like it was for x = 0

And due to how let's scope works, i and x are undefined by the time you reach a = [x, i, max] - the loops have ended and they’re no longer in scope

Edit to clarify: You were getting silent failures from undefineds in the max array, and the error messages were from the debugging


#5

Oh, thanks for pointing out the error with max[1], and reminding me about the scope of let!

I used a really dumb way to work around the max[1] error— after iterating through all values of the first subarray, I push the value 0 to max to have another value to compare to. As a consequence, max will always have a 0 as its last element, so I simply pop the last value off of max at the end of the function :wink:

function largestOfFour(arr){
	let max = [0];
	for (var x=0; x<arr.length; x++){
		for (var i = 0; i < arr[x].length; i++){
		if (arr[x][i]>max[x]){
			max[x] = arr[x][i];
		}
		}
		max.push(0);
	}	
max.pop();
return(max);

	}

Glad these scrappy edits worked, and thanks so much for pointing out all my mistakes along the way. I really appreciate you taking the time to do that. Now I’m curious to see how other people solve this!


#6

if you want to do it this way, why not initialise max to a larger array?

Additionally you might be aware of this already, but it’ll fail on arrays of entirely negative numbers, so you can kill two birds with one stone by initialising max to the 0th element of each of the subarrays


#7

Realized this doesn’t work with negative values, so I added anther cheeky edit and initially set max=[-10000] and did max.push(-10000) after looping over each subarray.

So it won’t work for arrays with values less than 10,000, but gets the job done for the challenge


#8

Now that you’ve essentially done it, you were curious about other answers to this, so here’s mine using the ES6 spread operator and arrow functions:

return arr.map(x => Math.max(...x));

#9

Ooh I like that! So initialize max to be an array with a length equal to that of the input array, and values corresponding to the first value of each subarray in the input array.

Trying to think of how I’d do that and came up with this:

function largestOfFour(arr){
	let max = new Array(arr.length);
	for (let a = 0; a<arr.length; a++){
    max[a] = arr[a][0]
} 
	for (var x=0; x<arr.length; x++){
		for (var i = 0; i < arr[x].length; i++){
		if (arr[x][i]>max[x]){
			max[x] = arr[x][i];
		}
		}
	}	
return(max);

	}

#10

Might be worth noting that you don’t need to start your second for loop from 0, it can now start from 1 :slight_smile:

Might be slightly nicer to read using forEach instead of for loops anyway, especially for the loop over x, avoids indexing entirely


#11

Wow that’s crazy simple. But also crazy complicated (to me…)

So your arrow function takes an input x and applies the max() function to x? And you use map() to let the function know that x should signify every subarray within arr?

Thanks again for sharing


#12

What’s a forEach loop? Is that covered in the class yet? I’ll check it out, thanks


#13

Essentially what it does is:

arr.map(someFunction) essentially does this:

const newArr = [];
for(let i=0; i<arr.length; i++) {
    newArr.push(someFunction(arr[i]);
}
return newArr;

In this case someFunction is x => Math.max(...x) where ...x is the spread operator and expands an array into the arguments of a function, and Math.max takes numbers and returns the maximum


just realised functional programming comes after basic algorithm scripting… I am sorry for bringing up stuff you’ve not seen yet


And just saw your last question:

Honestly I thought forEach was covered before basic algorithm scripting, but browsing through the curriculum just now I can’t see it? I could have sworn there’s a lesson on it… sorry for showing you things out of order


#14

Thanks for explaining that so well!!!

This has been super helpful for me