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

Posted

技术标签:

【中文标题】按字符串属性值对对象数组进行排序【英文标题】:Sort array of objects by string property value 【发布时间】:2010-11-10 21:10:09 【问题描述】:

我有一个 javascript 对象数组:

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

如何在 JavaScript 中按 last_nom 的值对它们进行排序?

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

【问题讨论】:

此脚本允许您这样做,除非您想编写自己的比较函数或排序器:thomasfrank.se/sorting_things.html 最快的方法是使用同构的sort-array 模块,它可以在浏览器和节点中本地工作,支持任何类型的输入、计算字段和自定义排序顺序。 objs.sort((a, b) => a.last_nom > b.last_nom && 1 || -1) 函数比较(a, b) if (a.last_nom b.last_nom ) 返回 1; 返回 0; objs.sort(比较); @RobertTalada 这是我的答案***.com/a/67021585/7012450 【参考方案1】:

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

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))

【讨论】:

或内联:objs.sort(function(a,b) return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0 );); 官方文档:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… return a.last_nom.localeCompare(b.last_nom) 也可以。 对于那些寻找字段为数字的排序的人,比较函数体:return a.value - b.value; (ASC) 请写短代码objs.sort((a, b) =&gt; a.last_nom &gt; b.last_nom &amp;&amp; 1 || -1)【参考方案2】:

如果您有重复的姓氏,您可以按名字排序-

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

【讨论】:

@BadFeelingAboutThis 返回 -1 或 1 是什么意思?我知道 -1 字面意思是仅通过语法 A 小于 B,但是为什么要使用 1 或 -1 呢?我看到每个人都在使用这些数字作为返回值,但为什么呢?谢谢。 @Chris22 返回负数意味着b 应该在数组中的a 之后。如果返回一个正数,则意味着a 应该在b 之后。如果返回0,则表示它们被视为相等。您可以随时阅读文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… @BadFeelingAboutThis 感谢您的解释和链接。信不信由你,在我在这里问这个问题之前,我使用1, 0, -1 搜索了各种sn-ps 代码。我只是没有找到我需要的信息。【参考方案3】:

除了使用自定义比较函数,您还可以使用自定义toString() 方法(由默认比较函数调用)创建对象类型:

function Person(firstName, lastName) 
    this.firtName = firstName;
    this.lastName = lastName;


Person.prototype.toString = function() 
    return this.lastName + ', ' + this.firstName;


var persons = [ new Person('Lazslo', 'Jamf'), ...]
persons.sort();

【讨论】:

【参考方案4】:

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

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"));

其实这已经回答了这个问题。因为很多人联系我,抱怨it doesn't work with multiple parameters,所以写下面的部分。

多个参数

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

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(...args));
    

这将启用:

MyArray.from(People).sortBy("Name", "-Surname");

【讨论】:

不错。这个答案现在有一个打字稿版本:***.com/a/68279093/8910547。保持(类型)安全! ?【参考方案5】:

underscore.js

使用下划线,它又小又棒……

sortBy_.sortBy(list, iterator, [context]) 返回排序后的副本 列表,按每个值的运行结果升序排列 通过迭代器。迭代器也可以是属性的字符串名称 排序依据(例如长度)。

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

var sortedObjs = _.sortBy( objs, 'first_nom' );

【讨论】:

大卫,你能编辑答案说,var sortedObjs = _.sortBy( objs, 'first_nom' );objs不会因此而自行排序。该函数将返回一个排序数组。这样会更明确。 反向排序:var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse(); 你需要加载javascript库“下划线”:&lt;script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"&gt; &lt;/script&gt; 对于喜欢那个的人也可以在Lodash 中找到 在 lodash 中这将是相同的:var sortedObjs = _.sortBy( objs, 'first_nom' ); 或者如果你想要它以不同的顺序:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );【参考方案6】:

使用原型继承简单快速地解决这个问题:

Array.prototype.sortBy = function(p) 
  return this.slice(0).sort(function(a,b) 
    return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
  );

示例/用法

objs = [age:44,name:'vinay',age:24,name:'deepak',age:74,name:'suresh'];

objs.sortBy('age');
// Returns
// ["age":24,"name":"deepak","age":44,"name":"vinay","age":74,"name":"suresh"]

objs.sortBy('name');
// Returns
// ["age":24,"name":"deepak","age":74,"name":"suresh","age":44,"name":"vinay"]

更新:不再修改原始数组。

【讨论】:

它不只是返回另一个数组。但实际上是对原来的排序!。 如果您想确保使用数字的自然排序(即 0、1、2、10、11 等),请使用带有 Radix 集的 parseInt。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 所以:返回 (parseInt(a[p],10) > parseInt(b[p],10)) ? 1 : (parseInt(a[p],10) @codehuntr 感谢您的纠正。但我想与其制作排序函数来进行这种敏感化,不如制作一个单独的函数来修复数据类型。因为排序函数不能不知道哪个属性会包含什么样的数据。 :) 非常好。反转箭头以获得 asc/desc 效果。 从不建议修改核心对象原型的解决方案【参考方案7】:

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;
    

【讨论】:

【参考方案8】:

将 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");

【讨论】:

感谢您的建议!顺便说一句,请不要鼓励人们更改 Array Prototype(请参阅示例末尾的警告)。【参考方案9】:

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

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

)

【讨论】:

【参考方案10】:

示例用法:

objs.sort(sortBy('last_nom'));

脚本:

/**
 * @description
 * Returns a function which will sort an
 * array of objects by the given key.
 *
 * @param  String  key
 * @param  Boolean reverse
 * @return Function
 */
const sortBy = (key, reverse) => 

  // Move smaller items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  const moveSmaller = reverse ? 1 : -1;

  // Move larger items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  const moveLarger = reverse ? -1 : 1;

  /**
   * @param  * a
   * @param  * b
   * @return Number
   */
  return (a, b) => 
    if (a[key] < b[key]) 
      return moveSmaller;
    
    if (a[key] > b[key]) 
      return moveLarger;
    
    return 0;
  ;
;

【讨论】:

谢谢你打破这个,我试图理解为什么数字 1, 0, -1 用于排序。即使上面有你的解释,看起来非常好——我还是不太明白。我一直认为-1 是在使用数组长度属性时,即:arr.length = -1 表示找不到该项目。我可能在这里混淆了,但你能帮我理解为什么数字1, 0, -1 用于确定顺序吗?谢谢。 这并不完全准确,但这样想可能会有所帮助:传递给 array.sort 的函数会为数组中的每个项目调用一次,如名为“a”的参数。每个函数调用的返回值是与下一个项目“b”相比,项目“a”的索引(当前位置编号)应该如何改变。索引指示数组的顺序(0、1、2 等)因此,如果“a”位于索引 5 并且您返回 -1,则 5 + -1 == 4(将其移近前面) 5 + 0 == 5 (保持在原处)等等。它遍历数组,每次比较 2 个邻居,直到到达末尾,留下一个排序数组。 感谢您抽出宝贵时间进一步解释这一点。因此,使用您的解释和MDN Array.prototype.sort,我会告诉您我的想法:与ab 相比,如果a 大于b,则在索引中添加1 a放在b后面,如果a小于b,把a减1放在b前面。如果ab 相同,则将0 加到a 并保留原处。【参考方案11】:

根据您的示例,您需要按两个字段(姓氏、名字)排序,而不是一个。您可以使用Alasql 库在一行中进行这种排序:

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

试试这个例子at jsFiddle。

【讨论】:

【参考方案12】:

使用 xPrototype:https://github.com/reduardo7/xPrototype/blob/master/README.md#sortbycol1-col2-coln

var o = [ 
   Name: 'Lazslo', LastName: 'Jamf'     ,
   Name: 'Pig',    LastName: 'Bodine'   ,
   Name: 'Pirate', LastName: 'Prentice' ,
   Name: 'Pag',    LastName: 'Bodine'   
];


// Original
o.each(function (a, b)  console.log(a, b); );
/*
 0 Object Name: "Lazslo", LastName: "Jamf"
 1 Object Name: "Pig", LastName: "Bodine"
 2 Object Name: "Pirate", LastName: "Prentice"
 3 Object Name: "Pag", LastName: "Bodine"
*/


// Sort By LastName ASC, Name ASC
o.sortBy('LastName', 'Name').each(function(a, b)  console.log(a, b); );
/*
 0 Object Name: "Pag", LastName: "Bodine"
 1 Object Name: "Pig", LastName: "Bodine"
 2 Object Name: "Lazslo", LastName: "Jamf"
 3 Object Name: "Pirate", LastName: "Prentice"
*/


// Sort by LastName ASC and Name ASC
o.sortBy('LastName'.asc, 'Name'.asc).each(function(a, b)  console.log(a, b); );
/*
 0 Object Name: "Pag", LastName: "Bodine"
 1 Object Name: "Pig", LastName: "Bodine"
 2 Object Name: "Lazslo", LastName: "Jamf"
 3 Object Name: "Pirate", LastName: "Prentice"
*/


// Sort by LastName DESC and Name DESC
o.sortBy('LastName'.desc, 'Name'.desc).each(function(a, b)  console.log(a, b); );
/*
 0 Object Name: "Pirate", LastName: "Prentice"
 1 Object Name: "Lazslo", LastName: "Jamf"
 2 Object Name: "Pig", LastName: "Bodine"
 3 Object Name: "Pag", LastName: "Bodine"
*/


// Sort by LastName DESC and Name ASC
o.sortBy('LastName'.desc, 'Name'.asc).each(function(a, b)  console.log(a, b); );
/*
 0 Object Name: "Pirate", LastName: "Prentice"
 1 Object Name: "Lazslo", LastName: "Jamf"
 2 Object Name: "Pag", LastName: "Bodine"
 3 Object Name: "Pig", LastName: "Bodine"
*/

【讨论】:

【参考方案13】:

我刚刚增强了Ege Özcan 的动态排序以深入了解对象。 如果数据看起来像这样:

obj = [
    
        a:  a: 1, b: 2, c: 3 ,
        b:  a: 4, b: 5, c: 6 
    ,
     
        a:  a: 3, b: 2, c: 1 ,
        b:  a: 6, b: 5, c: 4 
];

如果您想对 a.a 属性进行排序,我认为我的增强功能非常有用。我向这样的对象添加新功能:

Object.defineProperty(Object.prototype, 'deepVal', 
    enumerable: false,
    writable: true,
    value: function (propertyChain) 
        var levels = propertyChain.split('.');
        parent = this;
        for (var i = 0; i < levels.length; i++) 
            if (!parent[levels[i]])
                return undefined;
            parent = parent[levels[i]];
        
        return parent;
    
);

并改变了_dynamicSortreturn函数:

return function (a,b) 
        var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
        return result * sortOrder;
    

现在您可以按以下方式按 a.a. 排序:

obj.sortBy('a.a');

查看JSFiddle中的完整脚本

【讨论】:

【参考方案14】:

排序(更多)复杂的对象数组

由于您可能会遇到像这个数组这样更复杂的数据结构,我将扩展解决方案。

TL;DR

基于@ege-Özcan的很可爱的answer的更可插拔的版本。

问题

我遇到了以下问题,无法更改。我也不想暂时压平物体。我也不想使用下划线/lodash,主要是出于性能原因和自己实现它的乐趣。

var People = [
   Name: name: "Name", surname: "Surname", Middlename: "JJ",
   Name: name: "AAA", surname: "ZZZ", Middlename:"Abrams",
   Name: name: "Name", surname: "AAA", Middlename: "Wars"
];

目标

目标是主要按People.Name.name排序,其次按People.Name.surname排序

障碍

现在,在基本解决方案中,使用括号表示法来计算要动态排序的属性。但是,在这里,我们还必须动态地构造括号符号,因为您会期望像 People['Name.name'] 这样的东西会起作用 - 但事实并非如此。

另一方面,简单地执行People['Name']['name'] 是静态的,只允许您下降到第 n 层。

解决方案

这里的主要补充是遍历对象树并确定最后一个叶子的值,你必须指定,以及任何中间叶子。

var People = [
   Name: name: "Name", surname: "Surname", Middlename: "JJ",
   Name: name: "AAA", surname: "ZZZ", Middlename:"Abrams",
   Name: name: "Name", surname: "AAA", Middlename: "Wars"
];

People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [  Name:  name: 'AAA', surname: 'ZZZ' , Middlename: 'Abrams' ,
//    Name:  name: 'Name', surname: 'Surname' , Middlename: 'JJ' ,
//    Name:  name: 'Name', surname: 'AAA' , Middlename: 'Wars'  ]

// same logic as above, but strong deviation for dynamic properties 
function dynamicSort(properties) 
  var sortOrder = 1;
  // determine sort order by checking sign of last element of array
  if(properties[properties.length - 1][0] === "-") 
    sortOrder = -1;
    // Chop off sign
    properties[properties.length - 1] = properties[properties.length - 1].substr(1);
  
  return function (a,b) 
    propertyOfA = recurseObjProp(a, properties)
    propertyOfB = recurseObjProp(b, properties)
    var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
    return result * sortOrder;
  ;


/**
 * Takes an object and recurses down the tree to a target leaf and returns it value
 * @param  Object root - Object to be traversed.
 * @param  Array leafs - Array of downwards traversal. To access the value: parent: child: 'value' -> ['parent','child']
 * @param  Number index - Must not be set, since it is implicit.
 * @return String|Number       The property, which is to be compared by sort.
 */
function recurseObjProp(root, leafs, index) 
  index ? index : index = 0
  var upper = root
  // walk down one level
  lower = upper[leafs[index]]
  // Check if last leaf has been hit by having gone one step too far.
  // If so, return result from last step.
  if (!lower) 
    return upper
  
  // Else: recurse!
  index++
  // HINT: Bug was here, for not explicitly returning function
  // https://***.com/a/17528613/3580261
  return recurseObjProp(lower, leafs, index)


/**
 * Multi-sort your array by a set of properties
 * @param ...Array Arrays to access values in the form of: parent: child: 'value' -> ['parent','child']
 * @return Number Number - number for sort algorithm
 */
function dynamicMultiSort() 
  var args = Array.prototype.slice.call(arguments); // slight deviation to base

  return function (a, b) 
    var i = 0, result = 0, numberOfProperties = args.length;
    // REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
    // Consider: `.forEach()`
    while(result === 0 && i < numberOfProperties) 
      result = dynamicSort(args[i])(a, b);
      i++;
    
    return result;
  

示例

工作示例on JSBin

【讨论】:

为什么?这不是原始问题的答案,“目标”可以简单地用 People.sort((a,b)=> return a.Name.name.localeCompare(b.Name.name) || a.Name 来解决.surname.localeCompare(b.Name.surname) )【参考方案15】:
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"));

【讨论】:

请考虑编辑您的帖子,以添加更多关于您的代码的作用以及它为何能解决问题的说明。一个大部分只包含代码的答案(即使它正在工作)通常不会帮助 OP 理解他们的问题。【参考方案16】:

这是一个简单的问题,不知道为什么人们有这么复杂的解决方案。 一个简单的排序函数(基于快速排序算法):

function sortObjectsArray(objectsArray, sortKey)
        
            // Quick Sort:
            var retVal;

            if (1 < objectsArray.length)
            
                var pivotIndex = Math.floor((objectsArray.length - 1) / 2);  // middle index
                var pivotItem = objectsArray[pivotIndex];                    // value in the middle index
                var less = [], more = [];

                objectsArray.splice(pivotIndex, 1);                          // remove the item in the pivot position
                objectsArray.forEach(function(value, index, array)
                
                    value[sortKey] <= pivotItem[sortKey] ?                   // compare the 'sortKey' proiperty
                        less.push(value) :
                        more.push(value) ;
                );

                retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
            
            else
            
                retVal = objectsArray;
            

            return retVal;
        

使用示例:

var myArr = 
        [
             val: 'x', idx: 3 ,
             val: 'y', idx: 2 ,
             val: 'z', idx: 5 ,
        ];
myArr = sortObjectsArray(myArr, 'idx');

【讨论】:

如何在js中实现快速排序是一个简单的解决方案?简单的算法,但不是简单的解决方案。 它很简单,因为它不使用任何外部库,也不会改变对象的原型。在我看来,代码的长度对代码的复杂度没有直接影响 好吧,让我换个说法:如何重新发明***是一个简单的解决方案?【参考方案17】:

一个简单的方法:

objs.sort(function(a,b) 
  return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
);

请注意'.toLowerCase()' 是防止错误所必需的 在比较字符串时。

【讨论】:

你可以使用arrow functions让代码更优雅一点:objs.sort( (a,b) =&gt; b.last_nom.toLowerCase() &lt; a.last_nom.toLowerCase() ); 这是错误的,原因与here 解释的原因相同。 箭头函数不适合 ES5。大量的引擎仍然仅限于 ES5。就我而言,我发现上面的答案要好得多,因为我使用的是 ES5 引擎(由我的公司强制)【参考方案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)
);

【讨论】:

这个从 JS 1.1 开始就可以使用了,这个胖箭头是 ES6/2015 的。但在我看来仍然非常有用,也是最好的答案 @PratikKelwalkar:如果您需要反转,只需切换 a 和 b 比较:objs.sort((a, b) => b.last_nom.localeCompare(a.last_nom)); 如果值是数字,则不需要localeCompare。您可以使用标准的&gt; 运算符 - 就像@muasif80 的答案中提到的那样 - ***.com/a/67992215/6908282【参考方案19】:

警告!不推荐使用此解决方案,因为它不会产生排序数组。它留在这里以备将来参考,因为这个想法并不罕见。

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

【讨论】:

实际上它似乎不起作用,不得不使用接受的答案。排序不正确。【参考方案20】:

我遇到了排序对象数组的问题,随着值的优先级发生变化,基本上我想按人的年龄对数组进行排序,然后按姓氏 - 或者只是按姓氏,名字。 我认为与其他答案相比,这是最简单的解决方案。

通过调用 sortPeoples(['array', 'of', 'properties'], reverse=false) 来使用它

///////////////////////example array of peoples ///////////////////////

var peoples = [
    name: "Zach", surname: "Emergency", age: 1,
    name: "Nancy", surname: "Nurse", age: 1,
    name: "Ethel", surname: "Emergency", age: 1,
    name: "Nina", surname: "Nurse", age: 42,
    name: "Anthony", surname: "Emergency", age: 42,
    name: "Nina", surname: "Nurse", age: 32,
    name: "Ed", surname: "Emergency", age: 28,
    name: "Peter", surname: "Physician", age: 58,
    name: "Al", surname: "Emergency", age: 58,
    name: "Ruth", surname: "Registration", age: 62,
    name: "Ed", surname: "Emergency", age: 38,
    name: "Tammy", surname: "Triage", age: 29,
    name: "Alan", surname: "Emergency", age: 60,
    name: "Nina", surname: "Nurse", age: 58
];



//////////////////////// Sorting function /////////////////////
function sortPeoples(propertyArr, reverse) 
        function compare(a,b) 
            var i=0;
            while (propertyArr[i]) 
                if (a[propertyArr[i]] < b[propertyArr[i]])  return -1;
                if (a[propertyArr[i]] > b[propertyArr[i]])  return 1;
                i++;
            
            return 0;
            
        peoples.sort(compare);
        if (reverse)
            peoples.reverse();
        
    ;

////////////////end of sorting method///////////////
function printPeoples()
  $('#output').html('');
peoples.forEach( function(person)
 $('#output').append(person.surname+" "+person.name+" "+person.age+"<br>");
 )
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
  <html>
  <body>
<button onclick="sortPeoples(['surname']); printPeoples()">sort by ONLY by surname ASC results in mess with same name cases</button><br>
<button onclick="sortPeoples(['surname', 'name'], true); printPeoples()">sort by surname then name DESC</button><br>
<button onclick="sortPeoples(['age']); printPeoples()">sort by AGE ASC. Same issue as in first case</button><br>
<button onclick="sortPeoples(['age', 'surname']); printPeoples()">sort by AGE and Surname ASC. Adding second field fixed it.</button><br>
        
    <div id="output"></div>
    </body>
  </html>

【讨论】:

人员数组s :(【参考方案21】:

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

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

其中fn1, fn2, ... 是返回 [-1,0,1] 的排序函数。这导致“按 fn1 排序”、“按 fn2 排序”,这几乎等于 SQL 中的 ORDER BY。

此解决方案基于 || 运算符的行为,其计算结果为 first evaluated expression which can be converted to true。

最简单的形式只有一个这样的内联函数:

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

last_nom,first_nom 有两个步骤,排序顺序如下所示:

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

通用比较函数可能是这样的:

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

此功能可以扩展为支持数字字段、区分大小写、任意数据类型等。

您可以通过排序优先级链接它们来使用它:

// 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 可以带您走很长一段路,而无需外部库或复杂代码。它也非常有效,因为不必进行字符串解析

【讨论】:

【参考方案22】:

另一种选择:

var someArray = [...];

function generateSortFn(prop, reverse) 
    return function (a, b) 
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    ;


someArray.sort(generateSortFn('name', true));

默认升序排列。

【讨论】:

如果需要,这里提供了用于按多个字段排序的略微更改的版本:***.com/questions/6913512/… 它看起来可能是下一个: export function generateSortFn( prop: string, reverse: boolean = false ): (...args: any) => number return (a, b ) => 返回 a[prop] b[prop]?逆转 ? -1:1:0; ; 同意,但在某些情况下,我不需要查看实用功能。【参考方案23】:
// Sort Array of Objects

// Data
var booksArray = [
     first_nom: 'Lazslo', last_nom: 'Jamf'     ,
     first_nom: 'Pig',    last_nom: 'Bodine'   ,
     first_nom: 'Pirate', last_nom: 'Prentice' 
];

// Property to Sort By
var args = "last_nom";

// Function to Sort the Data by given Property
function sortByProperty(property) 
    return function (a, b) 
        var sortStatus = 0,
            aProp = a[property].toLowerCase(),
            bProp = b[property].toLowerCase();
        if (aProp < bProp) 
            sortStatus = -1;
         else if (aProp > bProp) 
            sortStatus = 1;
        
        return sortStatus;
    ;


// Implementation
var sortedArray = booksArray.sort(sortByProperty(args));

console.log("sortedArray: " + JSON.stringify(sortedArray) );

控制台日志输出:

"sortedArray: 
["first_nom":"Pig","last_nom":"Bodine",
"first_nom":"Lazslo","last_nom":"Jamf",
"first_nom":"Pirate","last_nom":"Prentice"]"

改编自此来源:http://www.levihackwith.com/code-snippet-how-to-sort-an-array-of-json-objects-by-property/

【讨论】:

【参考方案24】:

这将按字母数字顺序传递给它的属性对两级嵌套数组进行排序。

function sortArrayObjectsByPropAlphaNum(property) 
    return function (a,b) 
        var reA = /[^a-zA-Z]/g;
        var reN = /[^0-9]/g;
        var aA = a[property].replace(reA, '');
        var bA = b[property].replace(reA, '');

        if(aA === bA) 
            var aN = parseInt(a[property].replace(reN, ''), 10);
            var bN = parseInt(b[property].replace(reN, ''), 10);
            return aN === bN ? 0 : aN > bN ? 1 : -1;
         else 
            return a[property] > b[property] ? 1 : -1;
        
    ;

用法:

objs.sort(utils.sortArrayObjectsByPropAlphaNum('last_nom'));

【讨论】:

【参考方案25】:

我知道这个问题太老了,但我没有看到任何类似于我的实现。 此版本基于Schwartzian transform idiom。

function sortByAttribute(array, ...attrs) 
  // generate an array of predicate-objects contains
  // property getter, and descending indicator
  let predicates = attrs.map(pred => 
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return 
      getter: o => o[pred],
      descend: descending
    ;
  );
  // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
  return array.map(item => 
    return 
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    ;
  )
  .sort((o1, o2) => 
    let i = -1, result = 0;
    while (++i < predicates.length) 
      if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
      if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
      if (result *= predicates[i].descend) break;
    
    return result;
  )
  .map(item => item.src);

这是一个如何使用它的示例:

let games = [
   name: 'Mashraki',          rating: 4.21 ,
   name: 'Hill Climb Racing', rating: 3.88 ,
   name: 'Angry Birds Space', rating: 3.88 ,
   name: 'Badland',           rating: 4.33 
];

// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));

【讨论】:

【参考方案26】:

所以这是一种排序算法,它可以在任何类型的对象数组中以任何顺序排序,不受数据类型比较(即数字、字符串)的限制

function smoothSort(items,prop,reverse)   
    var length = items.length;
    for (var i = (length - 1); i >= 0; i--) 
        //Number of passes
        for (var j = (length - i); j > 0; j--) 
            //Compare the adjacent positions
            if(reverse)
              if (items[j][prop] > items[j - 1][prop]) 
                //Swap the numbers
                var tmp = items[j];
                items[j] = items[j - 1];
                items[j - 1] = tmp;
            
            

            if(!reverse)
              if (items[j][prop] < items[j - 1][prop]) 
                  //Swap the numbers
                  var tmp = items[j];
                  items[j] = items[j - 1];
                  items[j - 1] = tmp;
              
            
        
    

    return items;

第一个参数items是对象数组,

prop是要排序的对象的key,

reverse 是一个布尔参数,如果为 true,则按升序排列,如果为 false,则返回降序。

【讨论】:

【参考方案27】:

使用 Ramda,

npm install ramda

import R from 'ramda'
var objs = [ 
     first_nom: 'Lazslo', last_nom: 'Jamf'     ,
     first_nom: 'Pig',    last_nom: 'Bodine'   ,
     first_nom: 'Pirate', last_nom: 'Prentice' 
];
var ascendingSortedObjs = R.sortBy(R.prop('last_nom'), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)

【讨论】:

【参考方案28】:

我给你一个实现selectionSort算法的方案,简单有效

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


function selection_Sort(num)  
 //console.log(num);  
 var temp, index;
 for (var i = 0; i <= num.length - 1; i++) 
index = i;
for (var j = i + 1; j <= num.length - 1; j++) 
 // you can use first_nom/last_nom,any way you choose to sort

  if (num[j]. last_nom < num[index]. last_nom) 
    index = j;
   


//below is the swapping part
temp = num[i]. last_nom;
num[i]. last_nom = num[index]. last_nom;
num[index]. last_nom = temp;
 ;
 console.log(num); 
 return num; 
  
  selection_Sort(objs);

很高兴看到这么好的答案

【讨论】:

【参考方案29】:

Lodash.js(Underscore.js 的超集)

最好不要为每个简单的逻辑都添加框架,但是依靠经过良好测试的实用框架可以加快开发速度并减少错误数量。

Lodash 生成非常干净的代码,并提倡一种更函数式编程 风格。一眼就能看出代码的意图是什么。

OP 的问题可以简单地解决为:

const sortedObjs = _.sortBy(objs, 'last_nom');

更多信息?例如。我们有以下嵌套对象:

const users = [
   'user': 'name':'fred', 'age': 48,
   'user': 'name':'barney', 'age': 36 ,
   'user': 'name':'wilma',
   'user': 'name':'betty', 'age': 32
];

我们现在可以使用_.property 简写user.age 来指定应该匹配的属性的路径。我们将按嵌套的年龄属性对用户对象进行排序。是的,它允许嵌套属性匹配!

const sortedObjs = _.sortBy(users, ['user.age']);

想要反转吗?没问题。使用_.reverse。

const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));

想要使用chain 结合两者?

const  chain  = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();

或者你什么时候更喜欢flow而不是链

const  flow, reverse, sortBy  = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users); 

【讨论】:

【参考方案30】:

不正确的旧答案:

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

更新

来自 Beauchamp 的评论:

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() 将把true 转换为1false 转换为0

【讨论】:

它可以工作,但由于某种原因结果不稳定 @AO17 不会的。你不能减去字符串。 应该这样做:arr.sort((a, b) =&gt; a.name &lt; b.name ? -1 : (a.name &gt; b.name ? 1 : 0)) @Jean-FrançoisBeauchamp,您的解决方案效果很好,而且效果更好。 为什么arr.sort((a, b) =&gt; a.name &gt; b.name ? 1 : -1 不起作用?对于我已经测试过的字符串,这很好用。如果您想要不区分大小写,请使用 a.name.toLowerCase()b.name.toLowerCase()

以上是关于按字符串属性值对对象数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何按对象中的值对数组进行排序

在javascript中按子数组属性值对对象数组进行排序

根据字符串属性按字母顺序对对象数组进行排序

在Objective-C中按一个属性对自定义对象的NSSet进行排序

Javascript - 如何按 3 种不同的属性类型对对象数组进行排序? (字符串、整数、布尔值)

数组按对象属性排序