数组的更优雅的二级排序

时间:2015-12-03 20:29:36

标签: javascript arrays sorting

我需要对数组执行排序,如果两个元素相等,那么我需要对这些元素中的不同键执行二次排序。看一下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是否可以提供帮助。

3 个答案:

答案 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);