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

我有一个JavaScript对象数组:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

如何按last_nomJavaScript中的值对它们进行排序

我知道sort(a,b),但这似乎只适用于字符串和数字。我是否需要向toString()对象添加方法?

阳光樱前端2020/03/09 17:14:18
function compare(propName) {
    return function(a,b) {
        if (a[propName] < b[propName])
            return -1;
        if (a[propName] > b[propName])
            return 1;
        return 0;
    };
}

objs.sort(compare("last_nom"));
西门樱前端2020/03/09 17:14:18

您可能需要将它们转换为小写形式,以防止混淆。

objs.sort(function (a,b) {

var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()

if (nameA < nameB)
  return -1;
if (nameA > nameB)
  return 1;
return 0;  //no sorting

})
阿飞神乐2020/03/09 17:14:18
objs.sort(function(a,b){return b.last_nom>a.last_nom})
蛋蛋GO2020/03/09 17:14:18

将Ege的动态解决方案与Vinay的想法相结合,您将获得一个不错的强大解决方案:

Array.prototype.sortBy = function() {
    function _sortByAttr(attr) {
        var sortOrder = 1;
        if (attr[0] == "-") {
            sortOrder = -1;
            attr = attr.substr(1);
        }
        return function(a, b) {
            var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
            return result * sortOrder;
        }
    }
    function _getSortFunc() {
        if (arguments.length == 0) {
            throw "Zero length arguments not allowed for Array.sortBy()";
        }
        var args = arguments;
        return function(a, b) {
            for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
                result = _sortByAttr(args[i])(a, b);
            }
            return result;
        }
    }
    return this.sort(_getSortFunc.apply(null, arguments));
}

用法:

// Utility for printing objects
Array.prototype.print = function(title) {
    console.log("************************************************************************");
    console.log("**** "+title);
    console.log("************************************************************************");
    for (var i = 0; i < this.length; i++) {
        console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
    }
}

// Setup sample data
var arrObj = [
    {FirstName: "Zach", LastName: "Emergency", Age: 35},
    {FirstName: "Nancy", LastName: "Nurse", Age: 27},
    {FirstName: "Ethel", LastName: "Emergency", Age: 42},
    {FirstName: "Nina", LastName: "Nurse", Age: 48},
    {FirstName: "Anthony", LastName: "Emergency", Age: 44},
    {FirstName: "Nina", LastName: "Nurse", Age: 32},
    {FirstName: "Ed", LastName: "Emergency", Age: 28},
    {FirstName: "Peter", LastName: "Physician", Age: 58},
    {FirstName: "Al", LastName: "Emergency", Age: 51},
    {FirstName: "Ruth", LastName: "Registration", Age: 62},
    {FirstName: "Ed", LastName: "Emergency", Age: 38},
    {FirstName: "Tammy", LastName: "Triage", Age: 29},
    {FirstName: "Alan", LastName: "Emergency", Age: 60},
    {FirstName: "Nina", LastName: "Nurse", Age: 54}
];

//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");
泡芙Sam2020/03/09 17:14:18

EgeÖzcan代码的其他desc参数

function dynamicSort(property, desc) {
    if (desc) {
        return function (a, b) {
            return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
        }   
    }
    return function (a, b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}
Eva梅2020/03/09 17:14:18

这里有很多很好的答案,但我想指出,可以很简单地扩展它们,以实现更复杂的排序。您唯一要做的就是使用OR运算符来链接比较函数,如下所示:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Where fn1, fn2, ... are the sort functions which return [-1,0,1]. This results in "sorting by fn1", "sorting by fn2" which is pretty much equal to ORDER BY in SQL.

This solution is based on the behaviour of || operator which evaluates to the first evaluated expression which can be converted to true.

The simplest form has only one inlined function like this:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

Having two steps with last_nom,first_nom sort order would look like this:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

A generic comparision function could be something like this:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

This function could be extended to support numeric fields, case sensitity, arbitary datatypes etc.

You can them use it with chaining them by sort priority:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

这里的要点是,具有功能性方法的纯JavaScript可以使您走很长一段路,而无需外部库或复杂的代码。这也非常有效,因为不必进行字符串解析

宝儿小哥小卤蛋2020/03/09 17:14:18

旧答案不正确:

arr.sort((a, b) => a.name > b.name)

更新

从博尚的评论:

arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

更具可读性的格式:

arr.sort((a, b) => {
  if (a.name < b.name) return -1
  return a.name > b.name ? 1 : 0
})

没有嵌套的三元组:

arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))

说明:Number()将投true1false0

猴子小宇宙2020/03/09 17:14:18

如果您的姓氏重复,则可以按名字对它们进行排序-

obj.sort(function(a,b){
  if(a.last_nom< b.last_nom) return -1;
  if(a.last_nom >b.last_nom) return 1;
  if(a.first_nom< b.first_nom) return -1;
  if(a.first_nom >b.first_nom) return 1;
  return 0;
});
达蒙阳光乐2020/03/09 17:14:18

不知道为什么人们如此复杂:

objs.sort(function(a, b){
  return a.last_nom > b.last_nom;
});

对于更严格的引擎:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

交换运算符以按相反的字母顺序对其进行排序。

凯泡芙JinJin2020/03/09 17:14:18

您还可以创建一个动态排序函数,该函数根据传递的对象的值对它们进行排序:

function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        /* next line works with strings and numbers, 
         * and you may want to customize it to your needs
         */
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

因此,您可以拥有这样的对象数组:

var People = [
    {Name: "Name", Surname: "Surname"},
    {Name:"AAA", Surname:"ZZZ"},
    {Name: "Name", Surname: "AAA"}
];

...当您这样做时,它将起作用:

People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));

其实这已经回答了问题。下半部分是因为许多人联系我,抱怨它不适用于多个参数而写

多个参数

您可以使用下面的函数来生成具有多个排序参数的排序函数。

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;
    }
}

这将使您能够执行以下操作:

People.sort(dynamicSortMultiple("Name", "-Surname"));

子类化数组

对于可以使用ES6(允许扩展本机对象)的幸运者:

class MyArray extends Array {
    sortBy(...args) {
        return this.sort(dynamicSortMultiple.apply(null, args));
    }
}

这将启用以下功能:

MyArray.from(People).sortBy("Name", "-Surname");
JinJin阿飞番长2020/03/09 17:14:18

在ES6 / ES2015或更高版本中,您可以这样做:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));

在ES6 / ES2015之前

objs.sort(function(a, b) {
    return a.last_nom.localeCompare(b.last_nom)
});
神乐小胖2020/03/09 17:14:18

编写自己的比较函数很容易:

function compare( a, b ) {
  if ( a.last_nom < b.last_nom ){
    return -1;
  }
  if ( a.last_nom > b.last_nom ){
    return 1;
  }
  return 0;
}

objs.sort( compare );

或内联(c / o Marco Demaio):

objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0));