我需要对数组执行排序,如果两个元素相等,那么我需要对这些元素中的不同键执行二次排序。看一下array.sort的Mozilla开发者网络文档,底部的代码有一个很好的片段来处理第一种类型。我喜欢它,因为它很简洁,并展示了如何编写强大的JS。
以下是基于MDN代码的尝试。这正确地做了第一次。
attributedText
现在我知道我可以像这样修改比较函数来完成次要排序的要求:
// the array to be sorted
var list = [{name:'Delta', ref: 456}, {name:'Delta', ref: 123}, {name:'alpha', ref: 789}, {name:'CHARLIE', ref: 012}, {name:'bravo', ref: 345}];
// temporary array holds objects with position and sort-value
var mapped = list.map(function (el, i) {
return {
index: i,
value: el.name.toLowerCase(),
secondaryValue: el.ref
};
});
// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
return +(a.value > b.value) || +(a.value === b.value) - 1;
});
// container for the resulting order
var result = mapped.map(function (el) {
return list[el.index];
});
console.log(list);
console.log(result);
但是,对我来说,这会失去// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
if (a.value === b.value){
return +(a.secondaryValue > b.secondaryValue) || +(a.secondaryValue === b.secondaryValue) - 1;
}
return +(a.value > b.value) || - 1;
});
的一些魅力 - 我觉得这很酷。
问题:是否有更优雅的方式来执行辅助排序?
限制:仅限纯JS。 ES5兼容,但有兴趣听听ES6是否可以提供帮助。
答案 0 :(得分:5)
您可以使用逻辑或||
对排序比较进行链接,因为相同的值会被评估为0
,这是假的,因此会对下一部分进行评估。
mapped.sort(function (a, b) {
return (+(a.value > b.value) || +(a.value === b.value) - 1) ||
(+(a.secondaryValue > b.secondaryValue) || +(a.secondaryValue === b.secondaryValue) - 1);
});
或者使用上述比较的更紧凑版本
var list = [{name:'Delta', ref: 456}, {name:'Delta', ref: 123}, {name:'alpha', ref: 789}, {name:'CHARLIE', ref: 12}, {name:'bravo', ref: 345}],
mapped = list.map(function (el, i) {
return {
index: i,
value: el.name.toLowerCase(),
secondaryValue: el.ref
};
});
mapped.sort(function (a, b) {
return a.value.localeCompare(b.value) || a.secondaryValue - b.secondaryValue;
});
var result = mapped.map(function (el) {
return list[el.index];
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
答案 1 :(得分:1)
我正在回答这个问题,所以我将回答以下问题:
如何通过多个排序函数对数组进行简洁排序?
这个问题并不完全是你所要求的,但这样一来,它的定义和回答都会更好。
使用Array.prototype.sort
对使用单个函数的数组进行排序非常简单,但遗憾的是,它没有足够的前瞻性以允许多个参数。它还有直接修改数组而不是可链接的问题:
a = [2, 1, 3];
a.sort(function (a, b) {
return b - a;
});
按多维进行排序比较棘手,因为需要在sort
回调中考虑所有维度,或者您需要编写自己的排序算法,这很麻烦。
如果你正在使用下划线或lodash,有各种各样的排序工具可以方便,但如果你没有使用另一个库,multisort
功能并不是太难,你可以随意使用我快速掀起的那个我几乎没有测过的那个:
multisort = (function () {
// or for commonjs
// module.exports = (function () {
function slice(arr) {
return Array.prototype.slice.call(arr);
}
// multisort(arr, [fn1], [fn2] ...)
return function multisort(arr) {
var args;
//copy the arguments into a new array
args = slice(arguments);
//copy the array to a new array and sort the new array
return slice(arr).sort(function (a, b) {
var i,
fn,
res;
//iterate over the sort callbacks
for (i = 1; i < args.length; i++) {
fn = args[i];
//call the sort callback,
//this version doesn't do anything special with setting a context
res = fn(a, b);
//if the sort value is anything other than 0, return it
//otherwise fall to the next sort function
if (res) {
return res;
}
}
return 0;
});
}
}());
你将它用作:
mapped = multisort(mapped, function (a, b) {
return +(a.value > b.value) || +(a.value === b.value) - 1;
}, function (a, b) {
return +(a.secondaryValue > b.secondaryValue) || +(a.secondaryValue === b.secondaryValue) - 1;
});
这种格式使排序功能彼此不同,因此可以按照您喜欢的顺序混合和匹配它们。
答案 2 :(得分:0)
这样的帮手怎么样?
function thenby(comparer, func) {
return function (a, b) {
var intermidiate = comparer(a, b);
if (intermidiate)
return intermidiate;
else
return func(a, b)
};
}
然后你可以编写比较器并将它们串在一起
var comparer = function (a, b) {
return +(a.value > b.value) || +(a.value === b.value) - 1;
};
comparer = thenby(comparer, function (a, b) {
return +(a.secondaryValue > b.secondaryValue) || +(a.secondaryValue === b.secondaryValue) - 1;
});
mapped.sort(comparer);