从这个最初的问题,我将如何在多个字段应用排序?
使用这种稍作调整的结构,我将如何排序城市(上升)和价格(下降)?
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":"6",
"city":"Dallas",
"state":"TX",
"zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"zip":"00010",
"price":"962500"}
];
我喜欢的事实是,给出的答案提供了一个一般的方法。在我计划使用这段代码的地方,我将不得不对日期以及其他东西进行排序。“启动”对象的能力似乎很方便,如果不是有点麻烦的话。
我试图把这个答案构建成一个很好的通用示例,但我运气不太好。
这是一个完全的欺骗,但我认为它为这个问题增加了价值,因为它基本上是一个罐装的库函数,你可以开箱即用。
如果你的代码可以访问lodash或者一个与lodash兼容的库,比如下划线,那么你可以使用_。sortBy方法。下面的代码片段直接复制自lodash文档。
示例中的注释结果看起来像是返回数组的数组,但这只是显示了顺序,而不是实际的结果,它是一个对象数组。
var users = [
{ 'user': 'fred', 'age': 48 },
{ 'user': 'barney', 'age': 36 },
{ 'user': 'fred', 'age': 40 },
{ 'user': 'barney', 'age': 34 }
];
_.sortBy(users, [function(o) { return o.user; }]);
// => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
_.sortBy(users, ['user', 'age']);
// => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
另一种方式
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":"6",
"city":"Dallas",
"state":"TX",
"zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"zip":"00010",
"price":"962500"}
];
function sortBy(ar) {
return ar.sort((a, b) => a.city === b.city ?
b.price.toString().localeCompare(a.price) :
a.city.toString().localeCompare(b.city));
}
console.log(sortBy(homes));
改编自@chriskelly的回答。
大多数答案都忽略了,如果价值在1万美元以下或超过100万美元,价格将无法正确排序。原因是JS按字母顺序排序。这里回答得很好,为什么JavaScript不能对“5,10,1”排序,这里如何正确地对整数数组排序。
最后,如果我们要排序的字段或节点是一个数字,我们必须做一些计算。我并不是说在这种情况下使用parseInt()是正确的答案,排序结果更重要。
var homes = [{
"h_id": "2",
"city": "Dallas",
"state": "TX",
"zip": "75201",
"price": "62500"
}, {
"h_id": "1",
"city": "Dallas",
"state": "TX",
"zip": "75201",
"price": "62510"
}, {
"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"
}];
homes.sort(fieldSorter(['price']));
// homes.sort(fieldSorter(['zip', '-state', 'price'])); // alternative
function fieldSorter(fields) {
return function(a, b) {
return fields
.map(function(o) {
var dir = 1;
if (o[0] === '-') {
dir = -1;
o = o.substring(1);
}
if (!parseInt(a[o]) && !parseInt(b[o])) {
if (a[o] > b[o]) return dir;
if (a[o] < b[o]) return -(dir);
return 0;
} else {
return dir > 0 ? a[o] - b[o] : b[o] - a[o];
}
})
.reduce(function firstNonZeroValue(p, n) {
return p ? p : n;
}, 0);
};
}
document.getElementById("output").innerHTML = '<pre>' + JSON.stringify(homes, null, '\t') + '</pre>';
<div id="output">
</div>
用来测试的小提琴
以下是我的简历,请参考,并举例说明:
function msort(arr, ...compFns) {
let fn = compFns[0];
arr = [].concat(arr);
let arr1 = [];
while (arr.length > 0) {
let arr2 = arr.splice(0, 1);
for (let i = arr.length; i > 0;) {
if (fn(arr2[0], arr[--i]) === 0) {
arr2 = arr2.concat(arr.splice(i, 1));
}
}
arr1.push(arr2);
}
arr1.sort(function (a, b) {
return fn(a[0], b[0]);
});
compFns = compFns.slice(1);
let res = [];
arr1.map(a1 => {
if (compFns.length > 0) a1 = msort(a1, ...compFns);
a1.map(a2 => res.push(a2));
});
return res;
}
let tstArr = [{ id: 1, sex: 'o' }, { id: 2, sex: 'm' }, { id: 3, sex: 'm' }, { id: 4, sex: 'f' }, { id: 5, sex: 'm' }, { id: 6, sex: 'o' }, { id: 7, sex: 'f' }];
function tstFn1(a, b) {
if (a.sex > b.sex) return 1;
else if (a.sex < b.sex) return -1;
return 0;
}
function tstFn2(a, b) {
if (a.id > b.id) return -1;
else if (a.id < b.id) return 1;
return 0;
}
console.log(JSON.stringify(msort(tstArr, tstFn1, tstFn2)));
//output:
//[{"id":7,"sex":"f"},{"id":4,"sex":"f"},{"id":5,"sex":"m"},{"id":3,"sex":"m"},{"id":2,"sex":"m"},{"id":6,"sex":"o"},{"id":1,"sex":"o"}]
下面是我基于施瓦兹变换的解决方案,希望你觉得有用。
function sortByAttribute(array, ...attrs) {
// generate an array of predicate-objects contains
// property getter, and descending indicator
let predicates = attrs.map(pred => {
let descending = pred.charAt(0) === '-' ? -1 : 1;
pred = pred.replace(/^-/, '');
return {
getter: o => o[pred],
descend: descending
};
});
// schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
return array.map(item => {
return {
src: item,
compareValues: predicates.map(predicate => predicate.getter(item))
};
})
.sort((o1, o2) => {
let i = -1, result = 0;
while (++i < predicates.length) {
if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
if (result *= predicates[i].descend) break;
}
return result;
})
.map(item => item.src);
}
下面是一个如何使用它的例子:
let games = [
{ name: 'Pako', rating: 4.21 },
{ name: 'Hill Climb Racing', rating: 3.88 },
{ name: 'Angry Birds Space', rating: 3.88 },
{ name: 'Badland', rating: 4.33 }
];
// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));