Array sorting in Javascript with nested objects

I have an array of objects which I need to sort in 2 ways as stated below:

  1. Sort by alphabetical order using the country name.
  2. Inside every country sort scores in ascending order.

Below is the array and what I have tried to do.

//Structure of the Array
let allCountryScores=[
   {
      name: "Ethiopia", 
      scores:  [ {n: "Sub", s: 9990}, {n: "lucy", s: "4134234"}, {n: "DWH", s: 9999},  {n: "Hanif", s: 999999999} ]
    },     

]

//MY Code below

//Alphabetic ordering countries

let orderedCountries = allCountryScores.sort((a, b) => a.name.localeCompare(b.name));
//Numeric ordering of scores
let orderedScores = orderedCountries.forEach(country => { country.scores.sort((a, b) => a.s > b.s) });
console.log(orderedScores);

In my console, I am getting undefined. What could be wrong with my code?

Answer

There are two issues:

  1. forEach always returns undefined. You don’t need the assignment on that line, just remove it. (You also don’t need the assignment on the previous line, sort works on the array in place.)

  2. You’re not sorting the scores correctly, a.s > b.s doesn’t return what sort expects from its callback (a negative number if a should come before b, a positive number if a should come after b, or 0 if their order doesn’t matter). a.s - b.s does return that number.

Here’s an updated version assuming you’re happy to modify your original arrays:

//Alphabetic ordering countries
allCountryScores.sort((a, b) => a.name.localeCompare(b.name));
//Numeric ordering of scores
allCountryScores.forEach(country => { country.scores.sort((a, b) => a.s - b.s) });
console.log(allCountryScores);

Live Copy:

//Structure of the Array
let allCountryScores=[
   {
      name: "Ethiopia", 
      scores:  [ {n: "Sub", s: 9990}, {n: "lucy", s: "4134234"}, {n: "DWH", s: 9999},  {n: "Hanif", s: 999999999} ]
    },     

]

//Alphabetic ordering countries
allCountryScores.sort((a, b) => a.name.localeCompare(b.name));
//Numeric ordering of scores
allCountryScores.forEach(country => { country.scores.sort((a, b) => a.s - b.s) });
console.log(allCountryScores);
.as-console-wrapper {
    max-height: 100% !important;
}

If you want to create new arrays containing new objects with new arrays in them instead, you can do it like this:

const countries =
    allCountryScores.map(({name, scores}) => {
        // Copy and sort the scores
        scores = [...scores].sort((a, b) => a.s - b.s);
        // Return a new object
        return {name, scores};
    })
    // Sort that new array of countries
    .sort((a, b) => a.name.localeCompare(b.name));

Live Copy:

//Structure of the Array
let allCountryScores=[
   {
      name: "Ethiopia", 
      scores:  [ {n: "Sub", s: 9990}, {n: "lucy", s: "4134234"}, {n: "DWH", s: 9999},  {n: "Hanif", s: 999999999} ]
    },     

]

const countries =
    allCountryScores.map(({name, scores}) => {
        // Copy and sort the scores
        scores = [...scores].sort((a, b) => a.s - b.s);
        // Return a new object
        return {name, scores};
    })
    // Sort that new array of countries
    .sort((a, b) => a.name.localeCompare(b.name));

console.log(countries);
.as-console-wrapper {
    max-height: 100% !important;
}