7

I have an array:

var homes = [{
    "h_id": "3",
    "city": "Dallas",
    "state": "TX",
    "zip": "75201",
    "price": "162500"
}, {
    "h_id": "4",
    "city": "Bevery Hills",
    "state": "CA",
    "zip": "90210",
    "price": "319250"
}, {
    "h_id": "5",
    "city": "New York",
    "state": "NY",
    "zip": "00010",
    "price": "962500"
}];

And would like to sort it based on the following order

cities = ['New York', 'Dallas', 'Bevery Hills']

What's the best way to achieve it?

2
  • 1
    How about Array.prototype.sort()? Have you checked it already? Commented Nov 2, 2015 at 7:17
  • @diziaq done. cheers! Commented Jun 13, 2019 at 23:21

3 Answers 3

21

There is a standard method Array.prototype.sort() available.

Notice that the sort method does sorting in place, so internals of homes are going to change.

homes.sort(function (a,b){
  return cities.indexOf(a.city) - cities.indexOf(b.city)
});

If you need to keep the initial array unchanged, just make a shallow copy (homes.slice(0)) of it and sort the copy:

const sortedHomes = homes.slice(0).sort(function (a,b){
  return cities.indexOf(a.city) - cities.indexOf(b.city)
});
Sign up to request clarification or add additional context in comments.

Comments

4

Since you can use indexOf on cities to look up the final index of any home object, you can do it more efficiently than Array.prototype.sort:

var sortedHomes = new Array(cities.length);

homes.forEach(function (home) {
    var sortedIndex = cities.indexOf(home.city);
    sortedHomes[sortedIndex] = home;
});

(This is still O(nm) city name comparisons, time proportional to the product of the number of cities and the number of homes – an improvement over O(nm log n), but still potentially not good with a large number of cities. You can make it O(n) by flipping cities into a hashmap.)

If multiple homes can share the same city and cities doesn’t contain duplicate entries (seems the most likely situation if this is the case), you can group the homes by city and combine the result as specified by cities:

var homesByCity = {};

homes.forEach(function (home) {
    var cityHomes = homesByCity[home.city];

    if (cityHomes) {
        cityHomes.push(home);
    } else {
        cityHomes = homesByCity[home.city] = [home];
    }
});

var sortedHomes = [];

cities.forEach(function (city) {
    (homesByCity[city] || []).forEach(sortedHomes.push, sortedHomes);
});

(The approach is O(n) on the number of cities.)

3 Comments

What about the case where homes contains several objects in the same city?
They return in the same order they were in the original array. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
@ghybs: The answer for that, if necessary, depends on the format of cities.
1

I would suggest some functional programming to solve this. The snippet below should get you the result you are looking for.

var sorted = cities.map(function(city) {
    return homes.filter(function(home) {
        return home.city === city;
    });
});

First, map over the cities array to create a new array based on it. Second, for each city, find the corresponding item in the homes array and add that to the correct position in the sorted array.

2 Comments

Would that create an array of arrays of objects?
No, it gives you an array of objects that match the ones in homes but sorted in the order you asked for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.