Join the Stack Overflow Community
Stack Overflow is a community of 6.2 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I read the following objects using Ajax and stored them in 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"
    }
];

How do I create a function to sort the objects by the price property in ascending and descending order using only JavaScript?

share|improve this question

18 Answers 18

up vote 820 down vote accepted

Sort homes by price in ascending order:

homes.sort(function(a, b) {
    return parseFloat(a.price) - parseFloat(b.price);
});
share|improve this answer
27  
What about a string comparison? – Brig Mar 1 '12 at 19:26
81  
You can use string1.localeCompare(string2) for string comparison – bradvido May 27 '14 at 13:51
24  
Keep in mind that localeCompare() is case insensitive. If you want case sensitive, you can use (string1 > string2) - (string1 < string2). The boolean values are coerced to integer 0 and 1 to calculate the difference. – Don Kirkby May 1 '15 at 21:58
    
Is there a way to pass an argument to the compare function? Thought being to make this a reusable function to which I could pass the key on which to sort the object? – jlbriggs Jul 13 '15 at 15:00
1  
@jlbriggs: see Triptych's answer below – Stobor Jul 23 '15 at 12:52

Here's a more flexible version, which allows you to create reusable sort functions, and sort by any field.

var sort_by = function(field, reverse, primer){

   var key = primer ? 
       function(x) {return primer(x[field])} : 
       function(x) {return x[field]};

   reverse = !reverse ? 1 : -1;

   return function (a, b) {
       return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
     } 
}

Now you can sort by any field at will...

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"

}];

// Sort by price high to low
homes.sort(sort_by('price', true, parseInt));

// Sort by city, case-insensitive, A-Z
homes.sort(sort_by('city', false, function(a){return a.toUpperCase()}));
share|improve this answer
7  
nickb - you're misreading the code. sort_by runs in O(1), and returns a function used by the built-in sort (O(N log N)) to compare items in a list. The total complexity is O(n log n) * O(1) which reduces to O(n log n), or the same as a quick sort. – Triptych Oct 31 '11 at 7:04
31  
Excellent idea! A few issues: 1-A left parenthesis seems to be in the wrong place. 2-Setting the reverse looks reverse :) 3-Line break seems to cause issues. Overall, shouldn't that one-liner be return (A < B ? -1 : (A > B ? 1 : 0)) * [1,-1][+!!reverse]; ? – Halil Özgür Dec 9 '11 at 15:52
18  
Here is a working jsfiddle vesrion of this code: jsfiddle.net/dFNva/1 – Blake Mills Jan 17 '13 at 4:32
10  
I just found the explanation: + converts boolean to number; !! converts non-boolean to boolean. (dreaminginjavascript.wordpress.com/2008/07/04/28) So, [+!!reverse] provides an index for the [-1,1] array evaluating to either [-1,1][0] or [-1,1][1], which evaluates to -1 or 1. That's awesome, but confusing. – gfullam May 23 '14 at 15:24
4  
Here is a fiddle based on @Blake Mills' fiddle: jsfiddle.net/gfullam/sq9U7 | It fixes the bug noted by Abby and implements "then by" sorting requested by AlanJames using the Crockford method of passing in another sort by function call as an option. – gfullam May 23 '14 at 18:09

To sort it you need to create a comparator function taking two arguments. Then call the sort function with that comparator function as follows:

// a and b are object elements of your array
function mycomparator(a,b) {
  return parseInt(a.price, 10) - parseInt(b.price, 10);
}
homes.sort(mycomparator);

If you want to sort ascending switch the expressions on each side of the minus sign.

share|improve this answer
4  
Here's a reference to the built in Array sort method - w3schools.com/jsref/jsref_sort.asp – Kevin Hakanson Jun 11 '09 at 4:17
    
For me, sorting ascending went the way that was originally coded: a.price - b.price – dmonopoly Mar 8 '13 at 16:36
1  
And here's a reference that actually explains the topic instead of saying "it's too complicated, you won't understand it anyway": developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… – Roland Illig May 25 '14 at 20:30
    
parseInt may be a bad idea to use with price. Will it accurately sort non-integers? (15.10 or 15.15). I'd use parseFloat instead. – BeetleJuice Jun 21 at 4:48

for string sorting in case some one needs it,

var dataArr = {  

    "hello": [{
    "id": 114,
    "keyword": "zzzzzz",
    "region": "Sri Lanka",
    "supportGroup": "administrators",
    "category": "Category2"
}, {
    "id": 115,
    "keyword": "aaaaa",
    "region": "Japan",
    "supportGroup": "developers",
    "category": "Category2"
}]

};
var sortArray = dataArr['hello'];
sortArray.sort(function(a,b) {
    if ( a.region < b.region )
        return -1;
    if ( a.region > b.region )
        return 1;
    return 0;
} );
share|improve this answer
    
not sure why my answer marked as community wiki post :-( – Ishan Liyanage Apr 29 '15 at 11:29
1  
I'm guessing it was because the question itself was marked as community wiki. – trichoplax Jun 11 '15 at 13:30
    
Apparently, you made it a CW post: "Post Made Community Wiki by Ishan Liyanage" – Léo Lam Jul 14 '15 at 1:56
6  
I just googled this question myself. Thank you myself from the past! :-) – Ishan Liyanage Jan 19 at 3:18

You want to sort it in Javascript, right? What you want is the sort() function. In this case you need to write a comparator function and pass it to sort(), so something like this:

function comparator(a, b) {
    return parseInt(a["price"], 10) - parseInt(b["price"], 10);
}

var json = { "homes": [ /* your previous data */ ] };
console.log(json["homes"].sort(comparator));

Your comparator takes one of each of the nested hashes inside the array and decides which one is higher by checking the "price" field.

share|improve this answer
1  
That's not a correct comparator – Bergi Sep 1 '14 at 16:03
1  
Oh, you're right, thanks. I edited the answer to be correct. – Tim Gilbert Sep 10 '14 at 18:37
    
parseInt may be a bad idea to use with price. Will it accurately sort non-integers? (15.10 or 15.15). I'd use parseFloat instead. – BeetleJuice Jun 21 at 4:49

As this answer was previously upvoted, I will keep the original answer, but I highly recommend the new implementation of sortBy which sorts an array and allows multiple sort criteria (through Schwartzian transform) See this gist: sortBy.js

Creating the sorting function

var sortBy = (function () {

  const _defaults = {
    parser: (x) => x,
    desc: false
  };

  const isObject = (o) => o !== null && typeof o === "object";
  const isDefined = (v) => typeof v !== "undefined";

  //gets the item to be sorted
  function getItem (x) {
    const isProp = isObject(x) && isDefined(x[this.prop]);
    return this.parser(isProp ? x[this.prop] : x);
  }

  /**
   * Sorts an array of elements
   * @param  {Array} array: the collection to sort
   * @param  {Object} options: 
   *         options with the sort rules. It have the properties:
   *         - {String}   prop: property name (if it is an Array of objects)
   *         - {Boolean}  desc: determines whether the sort is descending
   *         - {Function} parser: function to parse the items to expected type
   * @return {Array}
   */
  return function (array, options) {
    if (!(array instanceof Array) || !array.length)
      return [];
    const opt = Object.assign({}, _defaults, options);
    opt.desc = opt.desc ? -1 : 1;
    return array.sort(function (a, b) {
      a = getItem.call(opt, a);
      b = getItem.call(opt, b);
      return opt.desc * (a < b ? -1 : +(a > b));
    });
  };

}());

Setting unsorted data

var data = [
  {date: "2011-11-14T16:30:43Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T17:22:59Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
  {date: "2011-11-14T16:53:41Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:48:46Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0,   type: "cash"},
  {date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"},
  {date: "2011-11-14T16:58:03Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-14T17:07:21Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0,   type: "cash"}
];

Using it

Arrange the array, by "date" as String

//sort by @date (ascending)
sortBy(data, { prop: "date" });

// first element expected
{ date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab" }

// last element expected
{ date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"}

If you want to ignore case sensitive, set the parser callback:

//sort by @type (ascending)
sortBy(data, {
    prop: "type",
    // ignore case sensitive
    parser: (t) => t.toUpperCase()
});

// first element expected
{ date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0, type: "cash" }

// last element expected
{ date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa" }

If you want to convert the "date" field as Date type:

//sort by @date (descending)
sortBy([].concat(data), {
    prop: "date",
    desc: true,
    parser: (d) => new Date(d)
});

// first element expected
{ date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"}

// last element expected
{ date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab" }

Thanks to @Ozesh by his feedback, the issue related to properties with falsy values was fixed.

share|improve this answer
1  
Good job..awesome – Saravanan Rajaraman Sep 28 '15 at 16:46
    
I added a new and more powerful implementation, allowing multiple sort, e.g. field1 ASC, after field2 DESC, after field3 DESC. The new sortBy method is an implementation of Schwartzian transform and you can find it here: gist: sortBy.js – jherax Apr 11 at 4:07
    
This seems to breaks when a field is null. – TSNev Aug 25 at 13:51
    
@TSNev could you please provide an example (jsfiddle, plunkr, etc)? I tried to replicate it with no success, null values were ordered at the end of array. – jherax Aug 25 at 17:11
1  
Thank you for your feedback @Ozesh, the sortBy version above is deprecated :) I have written a new and more powerful implementation for sorting arrays. Check this gist: sortBy – jherax yesterday

Use lodash.sortBy, (instructions using commonjs, you can also just put the script include-tag for the cdn at the top of your html)

var sortBy = require('lodash.sortby');
// or
sortBy = require('lodash').sortBy;

Descending order

var descendingOrder = sortBy( homes, 'price' ).reverse();

Ascending order

var ascendingOrder = sortBy( homes, 'price' );
share|improve this answer
    
Or const sortBy = require('lodash/sortBy'); let calendars = sortBy(calendarListResponse.items, cal => cal.summary); – mpen Oct 17 at 1:13

Here is a culmination of all answers above.

Fiddle validation: http://jsfiddle.net/bobberino/4qqk3/

var sortOn = function (arr, prop, reverse, numeric) {

    // Ensure there's a property
    if (!prop || !arr) {
        return arr
    }

    // Set up sort function
    var sort_by = function (field, rev, primer) {

        // Return the required a,b function
        return function (a, b) {

            // Reset a, b to the field
            a = primer(a[field]), b = primer(b[field]);

            // Do actual sorting, reverse as needed
            return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
        }

    }

    // Distinguish between numeric and string to prevent 100's from coming before smaller
    // e.g.
    // 1
    // 20
    // 3
    // 4000
    // 50

    if (numeric) {

        // Do sort "in place" with sort_by function
        arr.sort(sort_by(prop, reverse, function (a) {

            // - Force value to a string.
            // - Replace any non numeric characters.
            // - Parse as float to allow 0.02 values.
            return parseFloat(String(a).replace(/[^0-9.-]+/g, ''));

        }));
    } else {

        // Do sort "in place" with sort_by function
        arr.sort(sort_by(prop, reverse, function (a) {

            // - Force value to string.
            return String(a).toUpperCase();

        }));
    }


}
share|improve this answer

I also worked with some kind of rating and multiple fields sort:

arr = [
    {type:'C', note:834},
    {type:'D', note:732},
    {type:'D', note:008},
    {type:'F', note:474},
    {type:'P', note:283},
    {type:'P', note:165},
    {type:'X', note:173},
    {type:'Z', note:239},
];

arr.sort(function(a,b){        
    var _a = ((a.type==='C')?'0':(a.type==='P')?'1':'2');
    _a += (a.type.localeCompare(b.type)===-1)?'0':'1';
    _a += (a.note>b.note)?'1':'0';
    var _b = ((b.type==='C')?'0':(b.type==='P')?'1':'2');
    _b += (b.type.localeCompare(a.type)===-1)?'0':'1';
    _b += (b.note>a.note)?'1':'0';
    return parseInt(_a) - parseInt(_b);
});

Result

[
    {"type":"C","note":834},
    {"type":"P","note":165},
    {"type":"P","note":283},
    {"type":"D","note":8},
    {"type":"D","note":732},
    {"type":"F","note":474},
    {"type":"X","note":173},
    {"type":"Z","note":239}
]
share|improve this answer

If you use Underscore.js, try sortBy:

// price is of an integer type
_.sortBy(homes, "price"); 

// price is of a string type
_.sortBy(homes, function(home) {return parseInt(home.price);}); 
share|improve this answer

You can use the JavaScript sort method with a callback function:

function compareASC(homeA, homeB)
{
    return parseFloat(homeA.price) - parseFloat(homeB.price);
}

function compareDESC(homeA, homeB)
{
    return parseFloat(homeB.price) - parseFloat(homeA.price);
}

// Sort ASC
homes.sort(compareASC);

// Sort DESC
homes.sort(compareDESC);
share|improve this answer

For sorting a array you must define a comparator function. This function always be different on your desired sorting pattern or order(i.e. ascending or descending).

Let create some functions that sort an array ascending or descending and that contains object or string or numeric values.

function sorterAscending(a,b) {
    return a-b;
}

function sorterDescending(a,b) {
    return b-a;
}

function sorterPriceAsc(a,b) {
    return parseInt(a['price']) - parseInt(b['price']);
}

function sorterPriceDes(a,b) {
    return parseInt(b['price']) - parseInt(b['price']);
}

Sort numbers (alphabetically and ascending):

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();

Sort numbers (alphabetically and descending):

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
fruits.reverse();

Sort numbers (numerically and ascending):

var points = [40,100,1,5,25,10];
points.sort(sorterAscending());

Sort numbers (numerically and descending):

var points = [40,100,1,5,25,10];
points.sort(sorterDescending());

As above use sorterPriceAsc and sorterPriceDes method with your array with desired key.

homes.sort(sorterPriceAsc()) or homes.sort(sorterPriceDes())
share|improve this answer

While it is a bit of an overkill for just sorting a single array, this prototype function allows to sort Javascript arrays by any key, in ascending or descending order, including nested keys, using dot syntax.

(function(){
    var keyPaths = [];

    var saveKeyPath = function(path) {
        keyPaths.push({
            sign: (path[0] === '+' || path[0] === '-')? parseInt(path.shift()+1) : 1,
            path: path
        });
    };

    var valueOf = function(object, path) {
        var ptr = object;
        for (var i=0,l=path.length; i<l; i++) ptr = ptr[path[i]];
        return ptr;
    };

    var comparer = function(a, b) {
        for (var i = 0, l = keyPaths.length; i < l; i++) {
            aVal = valueOf(a, keyPaths[i].path);
            bVal = valueOf(b, keyPaths[i].path);
            if (aVal > bVal) return keyPaths[i].sign;
            if (aVal < bVal) return -keyPaths[i].sign;
        }
        return 0;
    };

    Array.prototype.sortBy = function() {
        keyPaths = [];
        for (var i=0,l=arguments.length; i<l; i++) {
            switch (typeof(arguments[i])) {
                case "object": saveKeyPath(arguments[i]); break;
                case "string": saveKeyPath(arguments[i].match(/[+-]|[^.]+/g)); break;
            }
        }
        return this.sort(comparer);
    };    
})();

Usage:

var data = [
    { name: { first: 'Josh', last: 'Jones' }, age: 30 },
    { name: { first: 'Carlos', last: 'Jacques' }, age: 19 },
    { name: { first: 'Carlos', last: 'Dante' }, age: 23 },
    { name: { first: 'Tim', last: 'Marley' }, age: 9 },
    { name: { first: 'Courtney', last: 'Smith' }, age: 27 },
    { name: { first: 'Bob', last: 'Smith' }, age: 30 }
]

data.sortBy('age'); // "Tim Marley(9)", "Carlos Jacques(19)", "Carlos Dante(23)", "Courtney Smith(27)", "Josh Jones(30)", "Bob Smith(30)"

Sorting by nested properties with dot-syntax or array-syntax:

data.sortBy('name.first'); // "Bob Smith(30)", "Carlos Dante(23)", "Carlos Jacques(19)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"
data.sortBy(['name', 'first']); // "Bob Smith(30)", "Carlos Dante(23)", "Carlos Jacques(19)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"

Sorting by multiple keys:

data.sortBy('name.first', 'age'); // "Bob Smith(30)", "Carlos Jacques(19)", "Carlos Dante(23)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"
data.sortBy('name.first', '-age'); // "Bob Smith(30)", "Carlos Dante(23)", "Carlos Jacques(19)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"

You can fork the repo: https://github.com/eneko/Array.sortBy

share|improve this answer

With ECMAScript 6 StoBor's answer can be done even more concise:

homes.sort((a, b) => a.price - b.price)
share|improve this answer

I recently wrote a universal function to manage this for you if you want to use it.

/**
 * Sorts an object into an order
 *
 * @require jQuery
 *
 * @param object Our JSON object to sort
 * @param type Only alphabetical at the moment
 * @param identifier The array or object key to sort by
 * @param order Ascending or Descending
 *
 * @returns Array
 */
function sortItems(object, type, identifier, order){

    var returnedArray = [];
    var emptiesArray = []; // An array for all of our empty cans

    // Convert the given object to an array
    $.each(object, function(key, object){

        // Store all of our empty cans in their own array
        // Store all other objects in our returned array
        object[identifier] == null ? emptiesArray.push(object) : returnedArray.push(object);

    });

    // Sort the array based on the type given
    switch(type){

        case 'alphabetical':

            returnedArray.sort(function(a, b){

                return(a[identifier] == b[identifier]) ? 0 : (

                    // Sort ascending or descending based on order given
                    order == 'asc' ? a[identifier] > b[identifier] : a[identifier] < b[identifier]

                ) ? 1 : -1;

            });

            break;

        default:

    }

    // Return our sorted array along with the empties at the bottom depending on sort order
    return order == 'asc' ? returnedArray.concat(emptiesArray) : emptiesArray.concat(returnedArray);

}
share|improve this answer
homes.sort(function(a, b){
  var nameA=a.prices.toLowerCase(), nameB=b.prices.toLowerCase()
  if (nameA < nameB) //sort string ascending
    return -1 
  if (nameA > nameB)
    return 1
  return 0 //default return value (no sorting)
})
share|improve this answer

Hi after reading this article, I made a sortComparator for my needs, with the functionality to compare more than one json attributes, and i want to share it with you.

This solution compares only strings in ascending order, but the solution can be easy extended for each attribute to support: reverse ordering, other data types, to use locale, casting etc

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"

}];

// comp = array of attributes to sort
// comp = ['attr1', 'attr2', 'attr3', ...]
function sortComparator(a, b, comp) {
    // Compare the values of the first attribute
    if (a[comp[0]] === b[comp[0]]) {
        // if EQ proceed with the next attributes
        if (comp.length > 1) {
            return sortComparator(a, b, comp.slice(1));
        } else {
            // if no more attributes then return EQ
            return 0;
        }
    } else {
        // return less or great
        return (a[comp[0]] < b[comp[0]] ? -1 : 1)
    }
}

// Sort array homes
homes.sort(function(a, b) {
    return sortComparator(a, b, ['state', 'city', 'zip']);
});

// display the array
homes.forEach(function(home) {
    console.log(home.h_id, home.city, home.state, home.zip, home.price);
});

and the result is

$ node sort
4 Bevery Hills CA 90210 319250
5 New York NY 00010 962500
3 Dallas TX 75201 162500

and another sort

homes.sort(function(a, b) {
    return sortComparator(a, b, ['city', 'zip']);
});

with result

$ node sort
4 Bevery Hills CA 90210 319250
3 Dallas TX 75201 162500
5 New York NY 00010 962500
share|improve this answer

protected by Samuel Liew Oct 5 '15 at 9:03

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?