按照两个数值字段对Javascript数组进行排序

132
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);      
    return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

这段代码按gsize从小到大对数组进行排序。

我该如何更改以首先按gsize排序,然后再按glow排序?


1
排序函数对正数、负数或零结果做出反应。因此,您可以只写:“return aSize - bSize”。这将是更简单和易读的代码。 - user474470
顶部答案,压缩:col0然后按col1(升序)对对象数组进行排序: myArray.sort(function(a,b){return a.col0-b.col0||a.col1-b.col1}); 另一个例子:按索引#0,#2,#1(降序)对数组的数组进行排序: myArray.sort(function(a,b){return b[0]-a[0]||b[2]-a[2]||b[1]-a[1]}); - ashleedawg
被更一般的“如何按多个字段对对象数组进行排序?”所覆盖。 - outis
19个回答

240
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

简化版本


太好了,简化了我的解决方案... https://dev59.com/B2025IYBdhLWcg3wST6Q#56982102 - Joseph Poirier
3
好的,干净利落!但它只适用于数字。 - Afanasii Kurakin
你能解释一下这里的逻辑吗?!对我来说,先按一个键的值对数组进行排序,然后再按另一个键的值对结果进行排序是有效的。 - KTM
3
逻辑如下:如果两个gsize相等,则条件的第一部分等于0,被视为false,执行条件的第二部分。 - Scalpweb
@Scalpweb 是的 :) 所以这个方法可以逐个排序具有任意数量键的数组,是吧?!很棒的技巧。 - KTM
如果你想了解为什么这个有效,你可能需要查看以下链接: https://medium.com/@safareli/pss-ordering-is-a-monoid-61a4029387e - Safareli

132
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);

    if(aSize == bSize)
    {
        return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
    }
    else
    {
        return (aSize < bSize) ? -1 : 1;
    }
});

3
为了更加精简地使用箭头语法而不使用其他答案中显示的非明显技巧:grouperArray.sort((a, b) => a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize)。为了使代码更易于理解,我们保留“==”测试的明确性。 - ToolmakerSteve

57
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

使用箭头语法的更短版本!


4
更简洁地说,去掉空格:grouperArray.sort((a,b)=>a.gsize-b.gsize||a.glow-b.glow); 该代码用于对grouperArray数组进行排序,先按gsize属性升序排列,若gsize相同则按glow属性升序排列。 - Captain Fantastic
1
如果你想了解为什么那样能够运行,你可能会想要查看 https://medium.com/@safareli/pss-ordering-is-a-monoid-61a4029387e - Safareli

16

我知道这个问题已经问过一段时间了,但我想添加我的解决方案。

该函数动态生成排序方法。只需提供每个可排序子属性的名称,以+/-作为前缀表示升序或降序。非常易于重用,并且不需要了解您组合的数据结构。可以制作成白痴式的 - 但似乎不必要。

function getSortMethod(){
    var _args = Array.prototype.slice.call(arguments);
    return function(a, b){
        for(var x in _args){
            var ax = a[_args[x].substring(1)];
            var bx = b[_args[x].substring(1)];
            var cx;

            ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
            bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;

            if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
            if(ax != bx){return ax < bx ? -1 : 1;}
        }
    }
}

示例用法:

items.sort(getSortMethod('-price','+priority','+name'));

这将首先按最低价格对items进行排序,如果价格相同,则选择具有最高priority的项目。如果优先级也相同,则通过项目的name来进一步排列。

其中items是类似于以下数组:

var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

实时演示: http://gregtaff.com/misc/multi_field_sort/

编辑:已解决Chrome问题。


为了避免出现“error TS2554: Expected 0 arguments, but got ..”,在TypeScript中使用此语法:https://dev59.com/rW855IYBdhLWcg3w1oHa#4116634 - Chananel P

7

我希望三目运算符(Ternary operator) ((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;) 让你感到困惑。你可以查看链接以更好地理解它。

在此之前,这是完整if/else代码:

grouperArray.sort(function (a, b) {
    if (a.gsize < b.gsize)
    {
        return -1;
    }
    else if (a.gsize > b.gsize)
    {
        return 1;
    }
    else
    {
        if (a.glow < b.glow)
        {
            return -1;
        }
        else if (a.glow > b.glow)
        {
            return 1;
        }
        return 0;
    }
});

6

以下是一个实现,适用于希望使用任意数量字段的人。

Array.prototype.sortBy = function (propertyName, sortDirection) {

    var sortArguments = arguments;
    this.sort(function (objA, objB) {

        var result = 0;
        for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {

            var propertyName = sortArguments[argIndex];
            result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;

            //Reverse if sort order is false (DESC)
            result *= !sortArguments[argIndex + 1] ? 1 : -1;
        }
        return result;
    });

}

基本上,您可以指定任意数量的属性名称/排序方向:

var arr = [{
  LastName: "Doe",
  FirstName: "John",
  Age: 28
}, {
  LastName: "Doe",
  FirstName: "Jane",
  Age: 28
}, {
  LastName: "Foo",
  FirstName: "John",
  Age: 30
}];

arr.sortBy("LastName", true, "FirstName", true, "Age", false);
//Will return Jane Doe / John Doe / John Foo

arr.sortBy("Age", false, "LastName", true, "FirstName", false);
//Will return John Foo / John Doe / Jane Doe

3
grouperArray.sort(function (a, b) {
  var aSize = a.gsize;
  var bSize = b.gsize;
  var aLow = a.glow;
  var bLow = b.glow;
  console.log(aLow + " | " + bLow);      
  return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
});

3
grouperArray.sort(function (a, b) {
     var aSize = a.gsize;     
     var bSize = b.gsize;     
     var aLow = a.glow;
     var bLow = b.glow;
     console.log(aLow + " | " + bLow);
     return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0); }); 

3

使用多个键进行动态操作的方法:

  • 从排序的每个列/键中过滤唯一值
  • 按顺序或反向排列
  • 根据indexOf(value)键值为每个对象添加权重宽度和零填充
  • 使用计算出的权重进行排序

enter image description here

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );

        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? (a < b) : (a > b ? 1 : 0);
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });

    return this;
}
});

用途:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

enter image description here


3
这里有一种使用递归来按照任意数量的排序字段进行排序的实现。你需要传入一个结果数组,其中包含要排序的结果对象,以及一个由排序对象组成的排序数组。每个排序对象必须有一个"select"键表示其排序的键名,还必须有一个"order"键,指示是"升序"还是"降序"。请看示例代码:
sortMultiCompare = (a, b, sorts) => {
    let select = sorts[0].select
    let order = sorts[0].order
    if (a[select] < b[select]) {
        return order == 'ascending' ? -1 : 1
    } 
    if (a[select] > b[select]) {
        return order == 'ascending' ? 1 : -1
    }
    if(sorts.length > 1) {
        let remainingSorts = sorts.slice(1)
        return this.sortMultiCompare(a, b, remainingSorts)
    }
    return 0
}

sortResults = (results, sorts) => {
    return results.sort((a, b) => {
        return this.sortMultiCompare(a, b, sorts)
    })
}

// example inputs
const results = [
    {
        "LastName": "Doe",
        "FirstName": "John",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Doe",
        "FirstName": "Jane",
        "MiddleName": "Bill"
    },
    {
        "LastName": "Johnson",
        "FirstName": "Kevin",
        "MiddleName": "Bill"
    }
]

const sorts = [
    {
        "select": "LastName",
        "order": "ascending"
    },
    {
        "select": "FirstName",
        "order": "ascending"
    },
    {
        "select": "MiddleName",
        "order": "ascending"
    }    
]

// call the function like this:
let sortedResults = sortResults(results, sorts)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接