0

I have an object containing countries, cities and shops in those cities. I want to show (later) countries sorted based on amount of cities in the country, which works (my code) and then I want to sort the cities based on the number of shops (so the city with most shops comes first). Ive tried for so long and just cant make it work because whatever I tried or do does not work. I need to access the 'shopNum' property and then access cities and sort but nothing I did/do works. Any help would be really great. Sorry if it seems maybe too basic but I tried for a while, researched etc and am kind of lost.

var data = {
  Italy: {
    cityNum: 2,
    Rome: {
      shops: ['Shop123', 'shopxyz'],
      shopNum: 2
    },
    Milan: {
      shops: ['Shop1', 'shopA', 'shopD'],
      shopNum: 3
    }
  },
  USA: {
    cityNum: 1,
    Chicago: {
      shops: ['Shop123', 'shopxyz', 'shopZ'],
      shopNum: 3
    },
  },
}

var sortedCountries = Object.keys(data).sort((a, b) => {
  return data[b]["cityNum"] - data[a]["cityNum"];
}) //works fine

var sortedShops = Object.values(data).map(x => {
  Object.values(Object.keys(x).map(item => {
    if (item !== "cityNum") {
      console.log(item)
      return item;
    }
  })).map(x => console.log("item x", x))
})

sortedCities 
javascripting
  • 993
  • 3
  • 19
  • 32
  • Hi, you would like to sort the shops per cities? Or sort all shops combined? – Ivan Dec 15 '18 at 14:32
  • 2
    Please provide desired result and data structure, making sure that you don't rely on the order of properties in objects (as they are really unordered). When order is needed, you need to use arrays. – trincot Dec 15 '18 at 14:41

2 Answers2

1

Plain objects are not the right structure to rely on a certain order of properties. If you want to sort those objects, you should use arrays instead. See for instance this Q&A for more on this.

So your target data structure will be different. At the same time you could do away with the properties cityNum and shopNum since they are redundant once you have arrays (which have a length property).

I would work from the inside out, and start creating the sorted arrays with cities, and then finally sort those sub structures based on the number of cities:

var data = {Italy: {cityNum: 2,Rome: {shops: ['Shop123', 'shopxyz'],shopNum: 2},Milan: {shops: ['Shop1', 'shopA', 'shopD'],shopNum: 3}},USA: {cityNum: 1,Chicago: {shops: ['Shop123', 'shopxyz', 'shopZ'],shopNum: 3},},}
var sortedCountries = Object.entries(data)
    .map(([country, cities]) => ({ 
        country, 
        cities: Object.keys(cities)
            .filter(prop => prop !== "cityNum")
            .sort((a, b) => cities[b].shops.length - cities[a].shops.length)
            .map(city => ({
                city,
                shops: cities[city].shops
            }))
    }))
    .sort((a, b) => b.cities.length - a.cities.length)
console.log(sortedCountries);
trincot
  • 211,288
  • 25
  • 175
  • 211
0

You could construct a new object called allCities with a .reduce containing all the cities. Then use the same sort function you used on cityNum but this time applied on allCities and on the property shopNum.

Here's the code:

const data={Italy:{cityNum:2,Rome:{shops:["Shop123","shopxyz"],shopNum:2},Milan:{shops:["Shop1","shopA","shopD"],shopNum:3}},USA:{cityNum:1,Chicago:{shops:["Shop123","shopxyz","shopZ"],shopNum:3}}};

const sortedCountries = Object.keys(data).sort((a, b) => {
  return data[b]["cityNum"] - data[a]["cityNum"];
});

const allShops = Object.values(data).reduce((allCities, country) => {
  
  // extract the cityNum from the country object, the rest are cities 
  const { cityNum, ...cities } = country;
  
  // return an object containing all cities + the cities from the current country 
  return { ...allCities, ...cities };

}, {});


const sortedShops = Object.keys(allShops).sort((a, b) => {
  return allShops[b]["shopNum"] - allShops[a]["shopNum"];
});

console.log(sortedCountries)
console.log(sortedShops);
Ivan
  • 11,733
  • 5
  • 35
  • 63