Javascript 排序函数。先排序,然后再排序

我有一个对象数组要排序。每个对象有两个参数: 强度和名称

objects = []
object[0] = {strength: 3, name: "Leo"}
object[1] = {strength: 3, name: "Mike"}

我想先按力量排序,然后按名字的字母顺序排序。我使用以下代码按第一个参数进行排序。那么如何按秒排序呢?

function sortF(ob1,ob2) {
if (ob1.strength > ob2.strength) {return 1}
else if (ob1.strength < ob2.strength){return -1}
return 0;
};

谢谢你的帮助。

(我使用 Array.sort ()和前面提到的 sortF 作为传递给它的排序比较函数。)

62551 次浏览

Expand your sort function to be like this;

function sortF(ob1,ob2) {
if (ob1.strength > ob2.strength) {
return 1;
} else if (ob1.strength < ob2.strength) {
return -1;
}


// Else go to the 2nd item
if (ob1.name < ob2.name) {
return -1;
} else if (ob1.name > ob2.name) {
return 1
} else { // nothing to split them
return 0;
}
}

A < and > comparison on strings is an alphabetic comparison.

function sortF(ob1,ob2) {
if (ob1.strength > ob2.strength) {return 1}
else if (ob1.strength < ob2.strength) {return -1}
else if (ob1.name > ob2.name) {return 1}
return -1;
};

EDIT: Sort by strength, then if strength is equal, sort by name. The case where strength and name are equal in both objects doesn't need to be accounted for seperately, since the final return of -1 indicates a less-than-or-equal-to relationship. The outcome of the sort will be correct. It might make it run faster or slower, I don't know. If you want to be explicit, just replace

return -1;

with

else if (ob1.name < ob2.name) {return -1}
return 0;

This little function is often handy when sorting by multiple keys:

cmp = function(a, b) {
if (a > b) return +1;
if (a < b) return -1;
return 0;
}

or, more concisely,

cmp = (a, b) => (a > b) - (a < b)

Which works because in javascript:

true - true // gives 0
false - false // gives 0
true - false // gives 1
false - true // gives -1

Apply it like this:

array.sort(function(a, b) {
return cmp(a.strength,b.strength) || cmp(a.name,b.name)
})

Javascript is really missing Ruby's spaceship operator, which makes such comparisons extremely elegant.

When I was looking for an answer to this very question, the answers I found on StackOverflow weren't really what I hoped for. So I created a simple, reusable function that does exactly this. It allows you to use the standard Array.sort, but with firstBy().thenBy().thenBy() style. https://github.com/Teun/thenBy.js

PS. This is the second time I post this. The first time was removed by a moderator saying "Please don't make promotional posts for your own work". I'm not sure what the rules are here, but I was trying to answer this question. I'm very sorry that it is my own work. Feel free to remove again, but please point me to the rule involved then.

Find 'sortFn' function below. This function sorts by unlimited number of parameters(such as in c#: SortBy(...).ThenBy(...).ThenByDesc(...)).

function sortFn() {
var sortByProps = Array.prototype.slice.call(arguments),
cmpFn = function(left, right, sortOrder) {
var sortMultiplier = sortOrder === "asc" ? 1 : -1;


if (left > right) {
return +1 * sortMultiplier;
}
if (left < right) {
return -1 * sortMultiplier;
}
return 0;
};




return function(sortLeft, sortRight) {
// get value from object by complex key
var getValueByStr = function(obj, path) {
var i, len;


//prepare keys
path = path.replace('[', '.');
path = path.replace(']', '');
path = path.split('.');


len = path.length;


for (i = 0; i < len; i++) {
if (!obj || typeof obj !== 'object') {
return obj;
}
obj = obj[path[i]];
}


return obj;
};


return sortByProps.map(function(property) {
return cmpFn(getValueByStr(sortLeft, property.prop), getValueByStr(sortRight, property.prop), property.sortOrder);
}).reduceRight(function(left, right) {
return right || left;
});
};
}


var arr = [{
name: 'marry',
LocalizedData: {
'en-US': {
Value: 10000
}
}
}, {
name: 'larry',
LocalizedData: {
'en-US': {
Value: 2
}
}
}, {
name: 'marry',
LocalizedData: {
'en-US': {
Value: 100
}
}
}, {
name: 'larry',
LocalizedData: {
'en-US': {
Value: 1
}
}
}];
document.getElementsByTagName('pre')[0].innerText = JSON.stringify(arr)


arr.sort(sortFn({
prop: "name",
sortOrder: "asc"
}, {
prop: "LocalizedData[en-US].Value",
sortOrder: "desc"
}));


document.getElementsByTagName('pre')[1].innerText = JSON.stringify(arr)
pre {
font-family: "Courier New" Courier monospace;
white-space: pre-wrap;
}
Before:
<pre></pre>
Result:
<pre></pre>

You could chain the sort order with logical OR.

objects.sort(function (a, b) {
return a.strength - b.strength || a.name.localeCompare(b.name);
});

With ES6 you can do

array.sort(function(a, b) {
return SortFn(a.strength,b.strength) || SortFn(a.name,b.name)
})


private sortFn(a, b): number {
return a === b ? 0 : a < b ? -1 : 1;
}

steve's answer, but prettier.

objects.sort(function(a,b)
{
if(a.strength > b.strength) {return  1;}
if(a.strength < b.strength) {return -1;}
if(a.name     > b.name    ) {return  1;}
if(a.name     < b.name    ) {return -1;}
return 0;
}

In 2018 you can use just sort() ES6 function, that do exactly, what you want. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Here is the function I use. It will do an arbitrary number.

function Sorter(){
  

var self = this;
this.sortDefs = [];
  

for (let i = 0; i < arguments.length; i++) {
// Runs 5 times, with values of step 0 through 4.
this.sortDefs.push(arguments[i]);
}
  

this.sort = function(a, b){
  

for (let i = 0; i < self.sortDefs.length; i++) {


if (a[self.sortDefs[i]] < b[self.sortDefs[i]]) {
return -1;
} else if (a[self.sortDefs[i]] > b[self.sortDefs[i]]) {
return 1
}
}
    

return 0;
}
}


data.sort(new Sorter('category','name').sort);