You could use a chained sorting approach by taking the delta of values until it reaches a value not equal to zero.
var data = [{ 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: "6", city: "Dallas", state: "TX", zip: "75000", price: "556699" }, { h_id: "5", city: "New York", state: "NY", zip: "00010", price: "962500" }];
data.sort(function (a, b) {
return a.city.localeCompare(b.city) || b.price - a.price;
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or, using es6, simply:
data.sort((a, b) => a.city.localeCompare(b.city) || b.price - a.price);
Answer from Nina Scholz on Stack OverflowFiddle: https://jsfiddle.net/seL5ysk9/2/
EDIT: In case anyone wants to attempt the full codewars exercise that spawned this question: https://www.codewars.com/kata/strings-mix/train/javascript
I have an array:
var merged = [
{ letter: 'e', count: 2, string: 1 },
{ letter: 'l', count: 2, string: 1 },
{ letter: 'o', count: 2, string: 1 },
{ letter: 'a', count: 1, string: 0 },
{ letter: 'd', count: 1, string: 1 },
{ letter: 'f', count: 1, string: 1 },
{ letter: 'g', count: 1, string: 2 },
{ letter: 'h', count: 1, string: 1 },
{ letter: 'k', count: 1, string: 2 },
{ letter: 'm', count: 1, string: 2 },
{ letter: 'n', count: 1, string: 1 },
{ letter: 'r', count: 1, string: 1 },
{ letter: 's', count: 1, string: 1 },
{ letter: 't', count: 1, string: 0 },
{ letter: 'u', count: 1, string: 2 }
];And I want it to be sorted to look like this:
[
{ letter: 'e', count: 2, string: 1 }, <== preserve ordering by count
{ letter: 'l', count: 2, string: 1 },
{ letter: 'o', count: 2, string: 1 },
{ letter: 'd', count: 1, string: 1 }, <== non-string 0: preserve alphabetical order within count #
{ letter: 'f', count: 1, string: 1 },
{ letter: 'g', count: 1, string: 2 },
{ letter: 'h', count: 1, string: 1 },
{ letter: 'k', count: 1, string: 2 },
{ letter: 'm', count: 1, string: 2 },
{ letter: 'n', count: 1, string: 1 },
{ letter: 'r', count: 1, string: 1 },
{ letter: 's', count: 1, string: 1 },
{ letter: 'u', count: 1, string: 2 },
{ letter: 'a', count: 1, string: 0 }, <== the string 0's are at the end
{ letter: 't', count: 1, string: 0 }, <== start alphabetical order again within string 0
];How do i make the 'string' 0 items come last within a group of equal 'counts' and then alphabetize those 'string' 0 items just within the string 0 items?
So basically it's organized first by count in descending order, then within count subgroups it's ordered alphabetically. I just don't know how to go to the next level and within each count number, group the string 0's at the end and put those in alphabetical order.
This was actually out of order first and I did a custom sort comparator function to organize by count then letter. Now I'm trying to run a second sort function just to target the string 0 items, but I don't know how--this is how far I got, which doesn't work:
merged.sort(function(a,b) {
if (a.count == b.count) {
if (a.string == 0 && b.string == 0) {
if (a.letter < b.letter) {
return -1;
} else if (a.letter > b.letter) {
return 1;
}
}
}
});javascript - How to sort array of objects in 3 parts in JS? - Stack Overflow
javascript - Sort array of objects by string property value - Stack Overflow
javascript - Sorting an array of objects by property values - Stack Overflow
javaScript: sorting an array with multiple object/properties - General - The freeCodeCamp Forum
You could use a chained sorting approach by taking the delta of values until it reaches a value not equal to zero.
var data = [{ 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: "6", city: "Dallas", state: "TX", zip: "75000", price: "556699" }, { h_id: "5", city: "New York", state: "NY", zip: "00010", price: "962500" }];
data.sort(function (a, b) {
return a.city.localeCompare(b.city) || b.price - a.price;
});
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or, using es6, simply:
data.sort((a, b) => a.city.localeCompare(b.city) || b.price - a.price);
for a non-generic, simple solution to your exact problem:
homes.sort(
function(a, b) {
if (a.city === b.city) {
// Price is only important when cities are the same
return b.price - a.price;
}
return a.city > b.city ? 1 : -1;
});
This isn't sorting, it's making different groups of elements.
Use a forEach loop and push the object onto a different array depending on the condition.
function groupByFavorites(array) {
let result = {
none: [],
one: [],
multiple: []
};
array.forEach(o => {
if (!o.favorites) { // undefined or empty
result.none.push(o);
} else if (o.favorites.length == 1) {
result.one.push(o);
} else {
result.multiple.push(o);
}
return result;
});
}
You can assign a number to each case, with the cases that should come first having lower numbers and then subtract the two when comparing.
function sortBy() {
const getOrder = ({favorites})=>favorites?.length === 1 ? 0 : !favorites?.length ? 1 : 2;
const cmp = (a, b) => (getOrder(a) - getOrder(b));
return list => list.sort(cmp);
}
const data = [{ rentalName: "Foo", favorites:[{}, {}, {}] }, { rentalName: "Bar", favorites:[{}] }, { rentalName: "Baz", favoriteslikes:[{}] }, { Name: "Plugh", favorites:[] }];
const sortByLikes = sortBy();
console.log(sortByLikes(data));
It's easy enough to write your own comparison function:
function compare( a, b ) {
if ( a.last_nom < b.last_nom ){
return -1;
}
if ( a.last_nom > b.last_nom ){
return 1;
}
return 0;
}
objs.sort( compare );
Or inline (c/o Marco Demaio):
objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0))
Or simplified for numeric (c/o Andre Figueiredo):
objs.sort((a,b) => a.last_nom - b.last_nom); // b - a for reverse sort
You can also create a dynamic sort function that sorts objects by their value that you pass:
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
/* next line works with strings and numbers,
* and you may want to customize it to your needs
*/
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
So you can have an array of objects like this:
var People = [
{Name: "Name", Surname: "Surname"},
{Name:"AAA", Surname:"ZZZ"},
{Name: "Name", Surname: "AAA"}
];
...and it will work when you do:
People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));
Actually this already answers the question. Below part is written because many people contacted me, complaining that it doesn't work with multiple parameters.
Multiple Parameters
You can use the function below to generate sort functions with multiple sort parameters.
function dynamicSortMultiple() {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
Which would enable you to do something like this:
People.sort(dynamicSortMultiple("Name", "-Surname"));
Subclassing Array
For the lucky among us who can use ES6, which allows extending the native objects:
class MyArray extends Array {
sortBy(...args) {
return this.sort(dynamicSortMultiple(...args));
}
}
That would enable this:
MyArray.from(People).sortBy("Name", "-Surname");
Sort homes by price in ascending order:
homes.sort(function(a, b) {
return parseFloat(a.price) - parseFloat(b.price);
});
Or after ES6 version:
homes.sort((a, b) => parseFloat(a.price) - parseFloat(b.price));
Some documentation can be found here.
For descending order, you may use
homes.sort((a, b) => parseFloat(b.price) - parseFloat(a.price));
Here's a more flexible version, which allows you to create reusable sort functions, and sort by any field.
const sort_by = (field, reverse, primer) => {
const 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...
const 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
console.log(homes.sort(sort_by('price', true, parseInt)));
// Sort by city, case-insensitive, A-Z
console.log(homes.sort(sort_by('city', false, (a) => a.toUpperCase()
)));
Run code snippetEdit code snippet Hide Results Copy to answer Expand