How does this .sort / 2D array demo work?

This code block breaks down the order of the .sort operation, but could someone walk me through how this is accomplished line by line?

let arr = [90, 1, 20, 14, 3, 55];
var sortRes = [];
var copy = arr.slice();
var inc = 0;
copy.sort((a, b) => {
  sortRes[inc] = [a, b, a - b];
  inc += 1;
  return a - b;
});

var p = 0;
for (var i = 0; i < inc; i++) {
  copy = arr.slice();
  copy.sort((a, b) => {
    p += 1;
    if (p <= i) {
      return a - b;
    } else {
      return false;
    }
  });
  p = 0;
  console.log(
    copy +
      " \t a: " +
      sortRes[i][0] +
      " \tb: " +
      sortRes[i][1] +
      "\tTotal: " +
      sortRes[i][2]
  );
}

First, I’m not sure if this example is actually “the best” example to explain the order of how the sort function works. I guess it depends on which part you want to understand. If you just want to use it with its comparative function there are other examples that are more straight forward. However, if your curious as to how it works under the hood then it this example might suffice. Its worth keeping in mind it might be easier to build your own sort function from scratch instead.

Also I formatted your code for readability and fixed 1 issue with it (no } brace at the end). I also duplicated it in a codepen so anyone can play around with it, to follow along.

Before getting started its worth providing some other links to some parts of the code that might be useful for parts of the code that might trip up someone learning beyond the core syntax:


let arr = [90, 1, 20, 14, 3, 55];
var sortRes = [];
var copy = arr.slice();
var inc = 0;
  • arr is the original starting array.
  • sortRes is an array we later use with inc to keep track of the changes sort applies.
  • copy is a shallow copy of the array created using slice. The sort applied later to copy sorts the array in place, as we later use arr and don’t want it sorted, the copy is created so we don’t mess up the original.
  • inc is a simple counter used to keep track of calls to the callback passed to the sort we will go into next.
copy.sort((a, b) => {
  sortRes[inc] = [a, b, a - b];
  inc += 1;
  return a - b;
});

This is the first .sort call that actually does multiple things beyond just sorting.

sortRes[inc] = [a, b, a - b]; updates the index inc with an array of multiple values at the same time. Another way to think of the [a, b, a - b] is actually whats called a tuple, which is similar to an array which can be thought of as a “finite group of elements”. JS doesn’t directly have a tuple, rather its just an array with finite values, with the only difference in how your using it.
Quickly going into the tuple, a and b are the 2 numbers being compared, and the result of a - b is also saved to keep track of how its sorted.

inc += 1;
return a - b;

going over the other 2 lines of the first sort callback updates the increment, so we can see each call of the sort and the a - b is the actual logic that the sort cares about. As mentioned in the docs:


    If compareFunction(a, b) returns less than 0, sort a to an index lower than b (i.e. a comes first).
    If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAScript standard only started guaranteeing this behavior in 2019, thus, older browsers may not respect this.
    If compareFunction(a, b) returns greater than 0, sort b to an index lower than a (i.e. b comes first).
    compareFunction(a, b) must always return the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned, then the sort order is undefined.

So essentially the return a - b line is telling sort to sort from the smallest integer to the largest.


Now onto the next for loop, there’s actually some code in this part that doesn’t do anything, which I point out

var p = 0;
for (var i = 0; i < inc; i++) {
  copy = arr.slice();
  copy.sort((a, b) => {
    p += 1;
    if (p <= i) {
      return a - b;
    } else {
      return false;
    }
  });
  //...other code
}

(I cut out the console log for now)

var p = 0;
for (var i = 0; i < inc; i++) {
  copy = arr.slice();
  • var p = 0 is another counter used iterate against i.
  • for (var i = 0; i < inc; i++) { this for loop iterates over all the inc we made earlier using i as its “counter”. Everything inside of this for loop is more or less done in relation to i which is “counting” to the number of inc we did earlier.
  • copy = arr.slice(); makes another shallow copy of the original arr and copy
 copy.sort((a, b) => {
    p += 1;
    if (p <= i) {
      return a - b;
    } else {
      return false;
    }
  });
  p = 0;
// console log

So here is the “fun” part, which IMO is the most confusing part of the entire code.

  • copy.sort((a, b) => { we start another “sort” of our new shallow copy of the copy array.
  • p += 1 increments the p counter again, keeping track of which iteration of the sort we are going thru for the given iteration as defined byi from the for loop. So for every i we sort the copy and for each call to sort we update the p counter.

finally this chunk:

if (p <= i) {
      return a - b;
    } else {
      return false;
    }

(mind you this is where I’m actually not 100% sure I know whats going on, as it depends on the behavior of returning false from the callback passed to sort)

essentially this block executes the same logic as the first sort until p is greater than or less than i (which if you remember is counting to inc). So it kinda just “throws away” executions with false which I believe is calculated to be 0 and thus doesn’t change the order of these 2 functions. I believe the purpose of this is print out the “execution” status of the arr, as once p <= i the sorting essentially “stops” allowing the console log to be shown later.

after executing sort the code resets p = 0 and moves onto the next iteration of sort.

And finally console.log prints out the steps up until that point.


So to abstract what this code is doing it does:

  1. sort the array and keep track of what its sorting
  2. iterate over the previous sorts to print out what each sort call is doing.

The reason why this breakdown is done “kinda confusing” is the fact the first sort call is somewhat of a “black box” in that if you want to see what the copy is at a given time you can’t until sort was already ran.

So hopefully that extensive breakdown helps ;D I had a good amount of free time go over the code and the code seemed interesting enough to really dive into it.

Keep learning, keep building :+1:

1 Like

Damn! That was thorough! Thanks, man. I think I understand it now. The parts that had me looking askance at this code were the need for 2 .slices(). Why did we need to create two “shallow” copies. And other one was the relationship between “p” the “i” and “inc”. But yeah, once again, thanks for taking the time to explain all of this!

1 Like

I do have one lingering question - why does the “p” need to be reset each time the for loop runs, and why does not resetting it cause the sort not to work?

The p is essentially used to “count” back up to where i is. This isn’t done by a loop but rather the 2nd sort, which makes it kinda off. So after p gets to i the sort stops sorting. To prepare for the next iteration via the for loop using i p is reset so sort can count back up to i via sort.

1 Like

So I did a console log on p and i, and it does look like p has to catch up to where i is during each loop iteration, so, for example, at the 4th iteration - the console.log(‘p’ + p, ‘i’ + i) looks like this p:1, i:4, p:2, i:4, p:3, i:4, p:4, i:4. Does this mean that the sort is sorting 4 times in that particular instance? And if so, is it retracing the sorts that it already did from the three previous sorts?