如何在 JavaScript 中按多个字段值对对象数组进行排序

12

我在stackoverflow上找到了一个很好的方法,可以根据对象的某个属性对数组进行排序,具体定义请参考:

使用JavaScript按字符串属性值对对象数组进行排序

使用这个函数可以完美地进行单一排序(在所有浏览器中),甚至是嵌套排序中的子排序,但是在Google Chrome中却不起作用!这里是Ege Özcan针对对象数组的排序例程。

function dynamicSort(property) { 
    return function (a,b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}

使用名为 "Data" 的数组(当然,我的数组有更多的对象对)...

var Data = [{Category: "Business", Value: "ABC"},{Category:"Personal", Value:"XYZ"}];

我可以通过这样做来获得一个正确的排序,其中顺序列出了每个类别中的所有值...

Data.sort(dynamicSort("Value"));
Data.sort(dynamicSort("Category"));

通过首先按 Value 排序,然后按 Category 排序,我的数组按照所有基于 Business 的值排好序,并将所有基于 Personal 的值列在其后。非常完美! 但是在 Chrome 中,数据按类别正确排序,但每个类别内的值的顺序似乎相当随机。

有没有人知道更好的方法来进行排序,可以在 Chrome 中正常工作呢?


2
按照 A 排序,然后再独立地按照 B 排序,并不等同于按照 A B 排序。如果在某些浏览器上可以工作,那只是偶然。 - Alnitak
6个回答

41

我创建了一个多参数版本的dynamicSort函数:

function dynamicSort(property) { 
    return function (obj1,obj2) {
        return obj1[property] > obj2[property] ? 1
            : obj1[property] < obj2[property] ? -1 : 0;
    }
}

function dynamicSortMultiple() {
    /*
     * save the arguments object as it will be overwritten
     * note that arguments object is an array-like object
     * consisting of the names of the properties to sort by
     */
    var props = arguments;
    return function (obj1, obj2) {
        var i = 0, result = 0, numberOfProperties = props.length;
        /* try getting a different result from 0 (equal)
         * as long as we have extra properties to compare
         */
        while(result === 0 && i < numberOfProperties) {
            result = dynamicSort(props[i])(obj1, obj2);
            i++;
        }
        return result;
    }
}

我创建了一个数组,如下所示:

var arr = [
    {a:"a",b:"a",c:"a"},
    {a:"b",b:"a",c:"b"},
    {a:"b",b:"a",c:"a"},
    {a:"b",b:"a",c:"b"},
    {a:"b",b:"b",c:"a"},
    {a:"b",b:"b",c:"b"},
    {a:"b",b:"b",c:"a"},
    {a:"b",b:"b",c:"b"},
    {a:"b",b:"b",c:"a"},
    {a:"b",b:"b",c:"b"},
    {a:"b",b:"b",c:"a"},
    {a:"c",b:"b",c:"b"},
    {a:"c",b:"c",c:"a"}
];

当我这样做时它起作用了,

arr.sort(dynamicSortMultiple("c","b","a"));

这里有一个可用的示例:http://jsfiddle.net/ZXedp/


1
这个问题涉及到JavaScript中按字段值对数组中的对象进行排序。以下是一个可行的解决方案,它可以处理具有多个属性的对象:https://dev59.com/UXNA5IYBdhLWcg3wAI3d#4760279 - Ege Özcan
你好,这个功能很棒,但是如何通过传递一个属性数组(例如["a", "b"])来实现,另一种情况是当属性需要大于某个值时,例如[{a: {gt: 5}}],“gt”表示“大于”。 - Luis Monsalve
@LuisDanielMonsalveRuiz 你可以使用dynamicSortMultiple(...myArray)函数。对于“大于”示例,您想要过滤结果,据我所知。您可能需要查看array.prototype.filter函数。 - Ege Özcan

8

执行JavaScript多标准排序或多参数排序的最简单方法是使用.sort,将多个参数连接在一起,然后比较这两个字符串。

例如:

data.sort(function (a, b) {

  var aConcat = a["property1"] + a["property2"];
  var bConcat = b["property1"] + b["property2"];

  if (aConcat > bConcat) {
    return 1;
  } else if (aConcat < bConcat) {
    return -1;
  } else {
    return 0;
  }

});

我在这里包含了一个JsFiddle脚本:http://jsfiddle.net/oahxg4u3/6/

3

我知道这篇文章很旧,但今天我找到了它并引用了Ege Özcan的话,我改进了他的优秀解决方案,为所有有兴趣的人实现了DESC-ASC SQL-Like功能 (http://jsfiddle.net/ZXedp/65/):

function dynamicSortMultiple() {
    var props=[];
    /*Let's separate property name from ascendant or descendant keyword*/
    for(var i=0; i < arguments.length; i++){
        var splittedArg=arguments[i].split(/ +/);
        props[props.length]=[splittedArg[0], (splittedArg[1] ? splittedArg[1].toUpperCase() : "ASC")];
    }
    return function (obj1, obj2) {
        var i = 0, result = 0, numberOfProperties = props.length ;
        /*Cycle on values until find a difference!*/
        while(result === 0 && i < numberOfProperties) {
            result = dynamicSort(props[i][0], props[i][1])(obj1, obj2);
            i++;
        }
        return result;
    }
}

/*Base function returning -1,1,0 for custom sorting*/
function dynamicSort(property, isAscDesc) { 
    return function (obj1,obj2) {
        if(isAscDesc==="DESC"){
            return ((obj1[property] > obj2[property]) ? (-1) : ((obj1[property] < obj2[property]) ? (1) : (0)));
        }
        /*else, if isAscDesc==="ASC"*/
        return ((obj1[property] > obj2[property]) ? (1) : ((obj1[property] < obj2[property]) ? (-1) : (0)));
    }
}

可以通过以下方式调用该函数:

arr.sort(dynamicSortMultiple("c DESC","b Asc","a"));

2

更好的写法:firstBy = (function() { function tb(y) { var x=this; function f(a,b) { return x(a,b)||y(a,b); } f.thenBy = tb; return f; } return function(f) { f.thenBy = tb; return f; }; })(); - Bergi
我对为什么这样更好很感兴趣。你能详细说明一下吗?也许可以使用拉取请求? - Teun D
  1. 只有一个共享的 thenBy 函数
  2. 没有不必要的 secondaryFunction
  3. 它更短
  4. 它更加实用,你的代码在处理 var a = firstBy(x), b = a.thenBy(y), c = a.thenBy(z) 时会出现问题,因为 a==b==c
- Bergi
我的版本已经缩减到137个字符。请参阅https://github.com/bergus/thenBy.js :-) - Bergi
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/34845/discussion-between-teun-d-and-bergi - Teun D
显示剩余2条评论

0

let obj = [{ name: "Gaurav" }, { name: "nidhu" }, { name: "Abhishek" }, { name: "cat" }, { name: "here" }];
for (let i = 0; i < obj.length; i++) {
  for (let j = 1; j < obj.length; j++) {
    if (obj[j - 1].name[0].toLowerCase() > obj[j].name[0].toLowerCase()) {
      let temp = obj[j - 1];
      obj[j - 1] = obj[j]
      obj[j] = temp
    }
  }
}
console.log(obj)


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0

这是我的解决方案。它比lodash的_.sortBy()多列排序函数快大约两倍(请参见http://jsperf.com/multi-column-sort)。 我生成排序函数的文本,然后在标准的.sort()中使用它。它在Chrome和Firefox中也可以工作。

function multiColumnSort(arr,sf) {
    var s = '';
    sf.forEach(function(f,idx) {
        s += 'if(arguments[0].'+f+'>arguments[1].'+f+')return 1;';
        s += 'else if(arguments[0].'+f+'==arguments[1].'+f+')';
        s += (idx < sf.length-1)? '{' : 'return 0';
    });
    s += Array(sf.length).join('}')+';return -1';
    return arr.sort(new Function(s));
};

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