-1

I am working through the array cardio challenge from Wes Bos Javascript 30 and am struggling to understand the behaviour of the sort() functions when run together or sequentially.

We start with an array of inventor objects and the initial challenge is to sort by birthdate.

The initial function (orderBirth) works as planned and returns the array sorted as expected.

Then we write another function (oldest) to sort the inventors array by age of inventor. This again works as expected.

However, if I re-run the console.log(orderBirth) it returns the array sorted by age rather than birthdate.

I understand that the sort function changes the original array (mutates it) but I can't understand why that would prevent the orderBirth function working correctly when run a second time.

const inventors = [
      { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
      { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
      { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
      { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
      { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
      { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
      { first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
      { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
      { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
      { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
      { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
      { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
    ];
    
const orderBirth = inventors.sort((a, b) => a.year > b.year ? 1 : -1);
    
console.log('Ordered by birthdate table')
console.log(orderBirth)

const oldest = inventors.sort((a, b) => {
      const lastInventor = a.passed - a.year;
      const nextInventor = b.passed - b.year;
      return lastInventor > nextInventor ? -1 : 1;
    });

console.log('Ordered by age')
console.log(oldest);

console.log('Re-running orderBirth gives unexpected result')
console.log(orderBirth)

I have read the post does-sort-function-change-original-array but while this explains the in place mutation of the sort function, it doesn't answer my question. Or at least it doesn't answer it with my current level of JS understanding.

whatapalaver
  • 865
  • 13
  • 25
  • please have alook here, too, regarding only two values as return value for sorting: https://stackoverflow.com/q/24080785/ – Nina Scholz Mar 03 '19 at 11:34
  • I don't think this is a duplicate question, they deal with the same issue but I understood that the sort function mutates the original array (and mentioned it my question). Where I became unstuck was in terms of the variable pointing to the same in-memory array and also the fact that I was never actually re-running the function. – whatapalaver Mar 03 '19 at 11:34

4 Answers4

1

Sort mutates the original array. so when you use sort sequentially eventually you're changing the same array again and again.

let arr = [1,2,3,5,6,64,76,52]

arr.sort((a,b)=> a-b)

console.log(arr)

You can create a copy of array and than sort it

let arr = [1,2,3,5,6,64,76,52]

let arr2 = [...arr].sort((a,b)=> a-b)

console.log(arr,arr2)
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
  • 1
    Maybe add that this happens even when assigning to a variable. – Jack Bashford Mar 03 '19 at 11:07
  • Thanks for the comment but why cant we continue to mutate the array with a different sort? So initially I sort by birth and the array is mutated. Then I sort by age and the array is mutated. Why would it stop there and not allow me to re-mutate by running the sort by birth function again? – whatapalaver Mar 03 '19 at 11:08
  • I think Jack may have given me the clue - I'm not re-running the function, I'm just re-logging the variable! Thanks for your help both. – whatapalaver Mar 03 '19 at 11:09
1

In JS, the array name only stores the reference to the original array. And sort mutates (changes) the array. You are not making a copy of the array with

const orderBirth = inventors.sort((a, b) => a.year > b.year ? 1 : -1);

Rather, you are storing the reference to the array sorted by year.

When you sort again with different function, the main array changes. And the orderBirth is still pointing to it. So that changes as well.

edit: As Scorpioo590 has said, .slice() method will duplicate the array.

const orderBirth = inventors.slice().sort((a, b) => a.year > b.year ? 1 : -1);

So what you assumed the '=' operator did is correctly achieved in this way.

Nirav
  • 560
  • 1
  • 7
  • 17
1

sort mutates the original array and returns the sorted array. So, they are all pointing to the same array in memory. Both of these will return true:

console.log(inventors === orderBirth)
console.log(oldest === orderBirth)

const inventors=[{first:'Albert',last:'Einstein',year:1879,passed:1955},{first:'Isaac',last:'Newton',year:1643,passed:1727},{first:'Galileo',last:'Galilei',year:1564,passed:1642},{first:'Marie',last:'Curie',year:1867,passed:1934},{first:'Johannes',last:'Kepler',year:1571,passed:1630},{first:'Nicolaus',last:'Copernicus',year:1473,passed:1543},{first:'Max',last:'Planck',year:1858,passed:1947},{first:'Katherine',last:'Blodgett',year:1898,passed:1979},{first:'Ada',last:'Lovelace',year:1815,passed:1852},{first:'Sarah E.',last:'Goode',year:1855,passed:1905},{first:'Lise',last:'Meitner',year:1878,passed:1968},{first:'Hanna',last:'Hammarström',year:1829,passed:1909}]
    
const orderBirth = inventors.sort((a, b) => a.year > b.year ? 1 : -1);

const oldest = inventors.sort((a, b) => {
      const lastInventor = a.passed - a.year;
      const nextInventor = b.passed - b.year;
      return lastInventor > nextInventor ? -1 : 1;
    });

console.log(inventors === orderBirth)
console.log(oldest === orderBirth)
adiga
  • 34,372
  • 9
  • 61
  • 83
1

As you mentioned the sort functions alters the original array.

With const orderBirth = inventors.sort(...) you get a reference to the array. Meaning both variables actually point to the same place in memory. Thus when changing the original array you also change the new variable. You would need to create a copy of the original array to preserve the result of the sorting.

const orderBirth = inventors.sort(...).slice();

should do the trick.

jBuchholz
  • 1,742
  • 2
  • 17
  • 25