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

Sort array of objects by string property value

提问人:Tyrone Slothrop 提问时间:7/15/2009 最后编辑:AdamTyrone Slothrop 更新时间:9/20/2023 访问量:3201866

问:

我有一个 JavaScript 对象数组:

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

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

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

JavaScript 排序 比较 字典数组

评论

2赞 Peter Mortensen 12/11/2022
区分大小写还是不区分大小写的排序?

答:

5661赞 Wogan 7/15/2009 #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))

或简化为数字 (c/o Andre Figueiredo):

objs.sort((a,b) => a.last_nom - b.last_nom); // b - a for reverse sort

评论

558赞 Marco Demaio 2/25/2010
或内联: objs.sort(function(a,b) {return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0);} );
45赞 mikemaccana 5/18/2012
官方文档:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/...
300赞 Cerbrus 2/14/2013
return a.last_nom.localeCompare(b.last_nom)也会起作用。
196赞 Andre Figueiredo 1/8/2014
对于那些查找字段为数字的排序的用户,比较函数体:(ASC)return a.value - b.value;
2赞 tbatch 4/8/2022
您可以使用 将字符串转换为数字,然后使用上面的数字内联以获得更简洁的一行: .这避免了丑陋的嵌套三元。charCodeAtobjs.sort((a,b) => a.last_nom.charCodeAt(0) - b.last_nom.charCodeAt(0));
89赞 kennebec 7/15/2009 #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;
});

评论

0赞 Chris22 8/22/2018
@BadFeelingAboutThis返回 -1 或 1 是什么意思?我知道 -1 的字面意思是 A 仅从语法上就小于 B,但为什么要使用 1 或 -1?我看到每个人都使用这些数字作为返回值,但为什么呢?谢谢。
1赞 BadFeelingAboutThis 8/23/2018
@Chris22返回的负数表示该数应在数组中排在后面。如果返回正数,则表示应该在 之后。如果返回,则表示它们被视为相等。您可以随时阅读文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...baab0
1赞 Chris22 8/23/2018
@BadFeelingAboutThis感谢您的解释和链接。信不信由你,在我在这里问这个问题之前,我用谷歌搜索了各种代码片段。我只是没有找到我需要的信息。1, 0, -1
36赞 Christoph 7/15/2009 #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();
1094赞 Ege Özcan 1/21/2011 #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"));

实际上,这已经回答了这个问题。下面的部分是因为很多人联系了我,抱怨它不适用于多个参数

多个参数

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

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

评论

10赞 Inigo 7/7/2021
好。现在有这个答案的 Typescript 版本:stackoverflow.com/a/68279093/8910547。保持(类型)安全!😉
0赞 zero_cool 7/2/2022
你永远不应该扩展 Array。
4赞 Ege Özcan 7/3/2022
@zero_cool Array 没有在这里扩展(原型保持不变),但它是从扩展的。你确实不应该改变原生对象的原型,但正如我所说,这里不会发生这种情况。
0赞 serge 9/30/2022
不测试 null
0赞 Ege Özcan 10/2/2022
@serge字符串和 null 的任何比较都会导致 false,将 null 值放在末尾。如果将 a[property] < b[property] 更改为 a[property].localeCompare(b[property]),则可以执行 a[property]?。localeCompare(b[property]) ??1(如果 a 在属性中为空,则首先取 b,如果 b 在属性中为 null,localeCompare 无论如何都会返回 -1 - 当两者都为 null 时不合逻辑,所以也检查一下)
244赞 David Morrow 5/11/2012 #5

下划线.js

使用下划线.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');

评论

23赞 Jess 1/9/2014
大卫,你能编辑答案说,. 不会因此而自行排序。该函数将返回一个排序后的数组。这将使它更加明确。var sortedObjs = _.sortBy( objs, 'first_nom' );objs
13赞 Erdal G. 1/31/2016
反向排序:var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
2赞 and-bri 5/30/2017
您需要加载 JavaScript 库“underscore”:<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>
7赞 WoJ 4/17/2018
Lodash 也适用于喜欢那个的人
7赞 Travis Heeter 11/16/2018
在 lodash 中,这将是相同的:或者如果您希望它以不同的顺序:var sortedObjs = _.sortBy( objs, 'first_nom' );var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
70赞 Vinay Aggarwal 7/10/2012 #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"}]

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

评论

8赞 Vinay Aggarwal 7/21/2012
它不只是返回另一个数组。但实际上对原来的那个进行了排序!
1赞 Paul 5/12/2015
如果要确保对数字(即 0、1、2、10、11 等)使用自然排序,请使用带有 Radix 集的 parseInt。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/......所以: return (parseInt(a[p],10) > parseInt(b[p],10)) ?1 : (parseInt(a[p],10) < parseInt(b[p],10)) ?-1 : 0;
0赞 Vinay Aggarwal 5/22/2015
@codehuntr 感谢您的更正。但我想与其制作排序函数来执行这种敏化,不如制作一个单独的函数来修复数据类型。因为排序函数不能不分辨哪个属性将包含什么样的数据。:)
1赞 Sonic Soul 11/9/2021
我认为这仅适用于某些道具类型..您需要添加日期/字符串处理等。即,如果 type 是字符串,则使用 return a.localCompare(b) 等。
0赞 emallove 1/7/2023
我假设的目的是制作数组的浅拷贝。.slice(0)
12赞 Behnam Shomali 9/17/2012 #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;
    }
}

评论

1赞 Peter Mortensen 12/11/2022
“desc”有什么用?“下降”“描述符”?别的?
16赞 Mike R 4/24/2013 #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));
}

Usage:

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

评论

1赞 Ege Özcan 5/10/2013
谢谢你的想法!顺便说一句,请不要鼓励人们更改数组原型(请参阅示例末尾的警告)。
10赞 Burak Keceli 8/14/2013 #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
})
29赞 Jamie Mason 4/30/2014 #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;
  };
};

评论

0赞 Chris22 8/22/2018
感谢您对此进行分解,我试图理解为什么使用数字进行排序。即使有你上面的解释,看起来非常好——我仍然不太明白。我总是认为使用数组长度属性时,即:意味着找不到该项目。我可能在这里混淆了东西,但你能帮我理解为什么使用数字来确定顺序吗?谢谢。1, 0, -1-1arr.length = -11, 0, -1
1赞 Jamie Mason 8/23/2018
并不完全准确,但这样想可能会有所帮助:传递给 array.sort 的函数为数组中的每个项目调用一次,作为名为“a”的参数。每个函数调用的返回值是与下一个项目“b”相比,项“a”的索引(当前位置编号)应如何更改。索引决定了数组的顺序(0、1、2 等),因此,如果“a”位于索引 5 处并且您返回 -1,则 5 + -1 == 4(将其移近前面)5 + 0 == 5(将其保留在原处)等。它每次都会遍历数组,比较 2 个邻居,直到到达末尾,留下一个排序的数组。
1赞 Chris22 8/24/2018
感谢您抽出宝贵时间进一步解释这一点。因此,使用您的解释和 MDN Array.prototype.sort,我将告诉您我对此的看法:与 和 相比,如果大于,则将 1 添加到索引中并将其放在后面,如果小于 ,则从中减去 1 并将其放在 前面。如果 和 相同,则将 0 加到并保留原处。ababababababa
8赞 agershun 12/18/2014 #11

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

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

JSFiddle 中试试这个例子。

5赞 Eduardo Cuomo 2/10/2015 #12

使用 xPrototype 的 sortBy

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"}
*/
3赞 Morteza Tourani 6/29/2015 #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 }
}];

如果你想对一个属性进行排序,我认为我的增强功能很有帮助。我向如下所示的对象添加新功能:

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

并更改了 _dynamicSort 的返回函数:

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 中的完整脚本。

18赞 eljefedelrodeodeljefe 8/10/2015 #14

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

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

TL;博士

是基于@ege-Özcan非常可爱的答案的更多可插拔版本。

问题

我遇到了以下情况,无法更改它。我也不想暂时压平物体。我也不想使用下划线/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.namePeople.Name.surname

障碍

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

另一方面,简单地做是静态的,只允许你进入第 n 级。People['Name']['name']

溶液

这里的主要新增功能是沿着对象树走下去,并确定您必须指定的最后一个叶子的值,以及任何中间叶子。

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://stackoverflow.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;
  }
}

JSBin 上的工作示例

评论

3赞 Tero Tolonen 5/4/2016
为什么?这不是原始问题的答案,“目标”可以简单地用 People.sort((a,b)=>{ return a.Name.name.localeCompare(b.Name.name) || a.Name.surname.localeCompare(b.Name.surname) })
9赞 Evgenii 10/29/2015 #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"));

评论

2赞 Drenmi 10/30/2015
请考虑编辑您的帖子,以添加更多有关您的代码的作用以及为什么它会解决问题的解释。一个主要只包含代码的答案(即使它有效)通常不会帮助 OP 理解他们的问题。
8赞 Gil Epshtain 11/19/2015 #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');

评论

6赞 Andrew 11/24/2015
如何在 js 中实现快速排序是一个简单的解决方案?简单的算法,但不是简单的解决方案。
0赞 Gil Epshtain 11/24/2015
这很简单,因为它不使用任何外部库,也不会改变对象的原型。在我看来,代码的长度对代码的复杂性没有直接影响
3赞 Roberto14 12/10/2015
好吧,让我尝试用不同的词:重新发明轮子是一个简单的解决方案吗?
13赞 Caio Ladislau 1/15/2016 #17

一个简单的方法:

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

看到这是防止错误所必需的 在比较字符串时。'.toLowerCase()'

评论

5赞 Sertage 5/24/2017
您可以使用箭头函数来让代码更优雅一些:objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
0赞 Patrick Roberts 7/18/2018
这是错误的,原因与此处解释的原因相同。
2赞 dylanh724 7/21/2018
箭头函数不值得 ES5 使用。大量的发动机仍然仅限于 ES5。就我而言,我发现上面的答案要好得多,因为我使用的是 ES5 引擎(由我的公司强制)
1031赞 Vlad Bezden 1/30/2016 #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)
});

评论

0赞 Gangula 10/30/2021
如果值为数字,则不需要 .您可以使用标准运算符 - 如@muasif80在答案中提到的 - stackoverflow.com/a/67992215/6908282localeCompare>
13赞 Roshni Bokade 3/8/2016 #19

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

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

评论

3赞 madprops 2/21/2017
实际上它似乎不起作用,不得不使用公认的答案。排序不正确。
2赞 jmwierzbicki 3/16/2016 #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>

评论

3赞 Penguin9 2/14/2017
一大群人:(
0赞 Peter Mortensen 12/11/2022
HTML 是假的。元素位于元素的外部。其余的答案是假的吗?headhtml
35赞 Tero Tolonen 5/5/2016 #21

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

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

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

此解决方案基于运算符的行为,该行为的计算结果为第一个计算的表达式,该表达式可以转换为 true||

最简单的形式只有一个内联函数,如下所示:

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

有两个步骤,排序顺序如下所示:last_nomfirst_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 可以在没有外部库或复杂代码的情况下走很长的路。它也非常有效,因为不需要进行字符串解析。

15赞 ravshansbox 6/26/2016 #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));

默认情况下,它按升序排序。

评论

1赞 ravshansbox 12/1/2016
如果需要,此处提供了按多个字段排序的略微更改的版本:stackoverflow.com/questions/6913512/...
0赞 Den Kerny 5/23/2020
看起来可能是下一个: export function generateSortFn( prop: string, reverse: boolean = false ): (...args: any) => number { return (a, b) => { return a[prop] < b[prop] ? 反转 ? 1 : -1 : a[prop] > b[prop] ? 反转 ? -1 : 1 : 0; }; }
0赞 Den Kerny 5/25/2020
同意,但在某些情况下,我不需要查看效用函数。
5赞 Luke Schoen 7/9/2016 #23

对对象数组进行排序

// 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 the 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"}]"

根据此来源改编:代码片段:如何按属性对 JSON 对象数组进行排序

2赞 depiction 9/9/2016 #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赞 a8m 11/6/2016 #25

我没有看到任何与我类似的实现。此版本基于 Schwartzian 变换习语

function sortByAttribute(array, ...attrs) {
  // Generate an array of predicate-objects containing
  // 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'));
2赞 Partha Roy 12/9/2016 #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;
}
  • 第一个参数是对象数组,

  • prop 是要排序的对象的键,

  • reverse 是一个布尔参数,如果为 true,则返回序,如果为 false,则返回序。

10赞 Sridhar Sg 7/5/2017 #27

使用 Ramda,

npm 安装 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)

评论

0赞 Peter Mortensen 12/11/2022
什么是拉姆达?你能添加一个对它的引用(例如,一个(非裸的)链接)吗?(但是 ******* 没有 ******* “编辑:”、“更新:”或类似 - 答案应该看起来像今天写的一样)。
1赞 sg28 8/27/2017 #28

我将为您提供一个实现选择排序算法的解决方案。它简单而有效。

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);
45赞 Nico Van Belle 8/30/2017 #29

Lodash下划线.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 速记来指定应匹配的属性的路径。我们将按嵌套的 age 属性对用户对象进行排序。是的,它允许嵌套属性匹配!user.age

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

想要逆转吗?没关系。使用 _.reverse

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

想用子把两者结合起来吗?

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

或者你什么时候更喜欢流动而不是链?

const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users);
66赞 Damjan Pavlica 10/20/2017 #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()true1false0

评论

1赞 TitanFighter 2/4/2018
它有效,但由于某种原因结果不稳定
16赞 Jean-François Beauchamp 8/29/2018
这应该可以做到:arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))
3赞 Muhammad Ahsan 1/22/2019
@Jean-FrançoisBeauchamp,您的解决方案运行良好,而且效果更好。
0赞 Kojo 1/16/2020
第三个带数字的很简单,很好!
2赞 muasif80 6/16/2021
为什么行不通?对于字符串,我已经测试过了,效果很好。如果您想要不区分大小写,请使用 和arr.sort((a, b) => a.name > b.name ? 1 : -1a.name.toLowerCase()b.name.toLowerCase()
12赞 Bob Stein 2/24/2018 #31

给定原始示例:

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

按多个字段排序:

objs.sort(function(left, right) {
    var last_nom_order = left.last_nom.localeCompare(right.last_nom);
    var first_nom_order = left.first_nom.localeCompare(right.first_nom);
    return last_nom_order || first_nom_order;
});

笔记

  • a.localeCompare(b)普遍支持,如果 ,则返回 -1,0,1。a<ba==ba>b
  • ||在最后一行中,优先于 .last_nomfirst_nom
  • 减法适用于数值字段:var age_order = left.age - right.age;
  • 否定到反序,return -last_nom_order || -first_nom_order || -age_order;
4赞 karthik006 3/26/2018 #32

使用 LodashUnderscore.js,这是小菜一碟:

const sortedList = _.orderBy(objs, [last_nom], [asc]); // Ascending or descending
12赞 Francois Girard 5/29/2018 #33

一个简单的函数,它按属性对对象数组进行排序:

function sortArray(array, property, direction) {
    direction = direction || 1;
    array.sort(function compare(a, b) {
        let comparison = 0;
        if (a[property] > b[property]) {
            comparison = 1 * direction;
        } else if (a[property] < b[property]) {
            comparison = -1 * direction;
        }
        return comparison;
    });
    return array; // Chainable
}

用法:

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

sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc

评论

0赞 Coder0997 3/24/2020
这个解决方案非常适合我进行双向排序。谢谢
7赞 Harun Or Rashid 5/30/2018 #34

方式1:

可以使用下划线.js。首先导入下划线

 import * as _ from 'underscore';
 let SortedObjs = _.sortBy(objs, 'last_nom');

方式2:使用比较功能。

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

objs.sort(compare);
72赞 0leg 6/4/2018 #35

截至 2018 年,有一个更短、更优雅的解决方案。只是使用。Array.prototype.sort() 中。

例:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});

评论

21赞 smcstewart 6/18/2018
在问题中,字符串用于比较,而不是数字。您的答案非常适合按数字排序,但不太适合按字符串进行比较。
0赞 0leg 3/26/2019
用于比较对象属性(在本例中为数字)可用于数据的不同时间。例如,正则表达式可用于比较相邻字符串的每一对。a.value - b.value
0赞 surendrapanday 12/10/2019
如果你需要按ID对它进行排序,这个实现是相当好的。 是的,你建议使用正则表达式来比较相邻的字符串,这使得解决方案更加复杂,而如果正则表达式与给定的解决方案一起使用,这个简单版本的目的将不是这样。简单是最好的。
5赞 chandan gupta 7/5/2018 #36

它对我有用。在这里,它将保持未定义到最后。

 function sort(items, property, direction) {

    function compare(a, b) {
      if(!a[property] && !b[property]) {
        return 0;
      } else if(a[property] && !b[property]) {
        return -1;
      } else if(!a[property] && b[property]) {
        return 1;
      } else {
        const value1 = a[property].toString().toUpperCase(); // ignore upper and lowercase
        const value2 = b[property].toString().toUpperCase(); // ignore upper and lowercase
        if (value1 < value2) {
          return direction === 0 ? -1 : 1;
        } else if (value1 > value2) {
          return direction === 0 ? 1 : -1;
        } else {
          return 0;
        }
        
      }
    }
    
    return items.sort(compare);
   } 
   
   var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: undefined, value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];
   console.log('Ascending Order:- ');
   console.log(sort(items, 'name', 0));
   console.log('Decending Order:- ');
   console.log(sort(items, 'name', 1));
    
    

42赞 Patrick Roberts 7/18/2018 #37

我还没有看到这种特定方法的建议,所以这里有一个我喜欢使用的简洁比较方法,它适用于这两种类型:stringnumber

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

const sortBy = fn => {
  const cmp = (a, b) => -(a < b) || +(a > b);
  return (a, b) => cmp(fn(a), fn(b));
};

const getLastName = o => o.last_nom;
const sortByLastName = sortBy(getLastName);

objs.sort(sortByLastName);
console.log(objs.map(getLastName));

解释sortBy()

sortBy()接受一个,它从对象中选择一个值进行比较,并返回一个可以传递给 Array.prototype.sort() 的函数。在此示例中,我们将比较 .每当我们收到两个对象时,例如fno.last_nom

a = { first_nom: 'Lazslo', last_nom: 'Jamf' }
b = { first_nom: 'Pig', last_nom: 'Bodine' }

我们将它们与 进行比较。鉴于(a, b) => cmp(fn(a), fn(b))

fn = o => o.last_nom

我们可以将比较函数扩展为 。由于逻辑 OR (|| 在 JavaScript 中的工作方式,等价于(a, b) => cmp(a.last_nom, b.last_nom)cmp(a.last_nom, b.last_nom)

if (a.last_nom < b.last_nom) return -1;
if (a.last_nom > b.last_nom) return 1;
return 0;

顺便说一句,这在其他语言中被称为三向比较“宇宙飞船”(<=>)运算符

最后,下面是不使用箭头函数的 ES5 兼容语法:

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

function sortBy(fn) {
  function cmp(a, b) { return -(a < b) || +(a > b); }
  return function (a, b) { return cmp(fn(a), fn(b)); };
}

function getLastName(o) { return o.last_nom; }
var sortByLastName = sortBy(getLastName);

objs.sort(sortByLastName);
console.log(objs.map(getLastName));

评论

0赞 MSOACC 7/9/2020
我喜欢这种方法,但我认为在这里使用 的简写是错误的。这是将多个语句压缩到一行代码中。用语句编写的替代方案将更具可读性,同时仍然相当简洁。我认为为了美观而牺牲可读性是错误的。-(fa < fb) || +(fa > fb)if
0赞 Patrick Roberts 7/9/2020
@MSOACC感谢您的意见,但我恭敬地不同意。其他语言实现了执行相同比较的三向比较运算符,因此只需在概念上将其视为 .fa <=> fb
0赞 rjanjic 10/9/2020
嘿帕特里克,我喜欢你的答案,但它只能与英文字符 () Think of => 一起使用,其中被推到最后。相反,您可能应该将比较函数更新为: => 干杯,感谢您的回答;-)const cmp = (a, b) => -(a < b) || +(a > b);["ä", "a", "c", "b"].sort(cmp)["a", "b", "c", "ä"]äconst cmp = (a, b) => a.localeCompare(b);["a", "ä", "b", "c"]
0赞 Patrick Roberts 10/10/2020
@rjanjic感谢您的反馈。我知道它根据 unicode 中字符的码位进行排序。但是,将其更改为 use 会删除对数字进行排序的功能,并且速度也明显变慢。localeCompare
44赞 Harshal Yeole 8/23/2018 #38

你可以使用 最简单的方法:Lodash

(https://lodash.com/docs/4.17.10#orderBy)

此方法与此方法类似,只是它允许指定要排序的迭代的排序顺序。如果未指定 orders,则所有值均按升序排序。否则,请指定“desc”的降序或“asc”的升序排序顺序。_.sortBy

参数

集合 (Array|Object):要循环访问的集合。 [迭代=[_.identity]](数组[]|函数[]|Object[]|string[]):要排序的迭代。 [订单](string[]):迭代的排序顺序。

返回

(Array):返回新的排序数组。


var _ = require('lodash');
var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];
    
_.orderBy(homes, ['city', 'state', 'zip'], ['asc', 'desc', 'asc']);

评论

0赞 1111161171159459134 8/15/2023
在这里,这不会传递负数。
1赞 Mas 3/17/2019 #39

如果您有嵌套对象

const objs = [{
        first_nom: 'Lazslo',
        last_nom: 'Jamf',
        moreDetails: {
            age: 20
        }
    }, {
        first_nom: 'Pig',
        last_nom: 'Bodine',
        moreDetails: {
            age: 21
        }
    }, {
        first_nom: 'Pirate',
        last_nom: 'Prentice',
        moreDetails: {
            age: 22
        }
    }];

nestedSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
        const a = prop2 ? e1[prop1][prop2] : e1[prop1],
            b = prop2 ? e2[prop1][prop2] : e2[prop1],
            sortOrder = direction === "asc" ? 1 : -1
        return (a < b) ? -sortOrder : (a > b) ? sortOrder : 0;
    }

并称它为

objs.sort(nestedSort("last_nom"));
objs.sort(nestedSort("last_nom", null, "desc"));
objs.sort(nestedSort("moreDetails", "age"));
objs.sort(nestedSort("moreDetails", "age", "desc"));
3赞 Ferrybig 5/7/2019 #40

TypeScript 中编程时也可以制作动态排序函数,但在这种情况下类型变得更加棘手。

function sortByKey<O>(key: keyof O, decending: boolean = false): (a: O, b: O) => number {
    const order = decending ? -1 : 1;
    return (a, b): number => {
        const valA = a[key];
        const valB = b[key];
        if (valA < valB) {
            return -order;
        } else if (valA > valB) {
            return order;
        } else {
            return 0;
        }
    }
}

这可以在 TypeScript 中使用,如下所示:

const test = [
    {
        id: 0,
    },
    {
        id: 2,
    }
]

test.sort(sortByKey('id')) // OK
test.sort(sortByKey('id1')) // ERROR
test.sort(sortByKey('')) // ERROR
3赞 Jadli 11/19/2019 #41

此排序函数可用于所有对象排序:

  • 对象
  • deep对象
  • 数值数组

您还可以通过将 1、-1 作为参数传递来执行升序或降序排序。

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

function dynamicSortAll(property, sortOrders=1) {

    /** The default sorting will be ascending order. If
        you need descending order sorting you have to
        pass -1 as the parameter **/

    var sortOrder = sortOrders;

    return function (a, b) {

        var result = (property? ((a.deepVal(property) > b.deepVal(property)) ? 1 : (a.deepVal(property) < b.deepVal(property)) ? -1 : 0) : ((a > b) ? 1 : (a < b) ? -1 : 0))

        return result * sortOrder;
    }
}

deepObj = [
    {
        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 }
}];

let deepobjResult = deepObj.sort(dynamicSortAll('a.a', 1))
console.log('deepobjResult: ' + JSON.stringify(deepobjResult))
var obj = [
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];
let objResult = obj.sort(dynamicSortAll('last_nom', 1))
console.log('objResult: ' + JSON.stringify(objResult))

var numericObj = [1, 2, 3, 4, 5, 6]

let numResult = numericObj.sort(dynamicSortAll(null, -1))
console.log('numResult: ' + JSON.stringify(numResult))

let stringSortResult = 'helloworld'.split('').sort(dynamicSortAll(null, 1))

console.log('stringSortResult: ' + JSON.stringify(stringSortResult))

let uniqueStringOrger=[...new Set(stringSortResult)];
console.log('uniqueStringOrger: ' + JSON.stringify(uniqueStringOrger))

2赞 SwiftNinjaPro 11/25/2019 #42

下面是一个函数,可用于按多个对象对列表进行排序,如果第一个对象相等,则第二个顺序将用作回退。如果可能,也应忽略空值以回退顺序。

function sortObjects(list, orderBy){
    list.sort(function(a, b){
        let byIndex = 0;
        let order = orderBy[byIndex];
        while(!a[order.by] || !b[order.by] || a[order.by] === b[order.by]){
            byIndex++;
            if(byIndex >= orderBy.length){break;}
            order = orderBy[byIndex];
        }
        if(!a[order.by] || !b[order.by] || a[order.by] === b[order.by]){
            return false;
        }
        if(order.desc){
            return a[order.by] < b[order.by];
        }
        return a[order.by] > b[order.by];
    });
    return list;
}

用法:

var objs = [
    {a: 10, b: 20, c: 30},
    {a: 30, b: 10, c: 20},
    {a: 20, b: 10, c: 30},
];

sortObjectList(objs, [{by: 'a'}]);
[
    {a: 10, b: 20, c: 30},
    {a: 20, b: 10, c: 30},
    {a: 30, b: 10, c: 20},
]

sortObjectList(objs, [{by: 'a', desc: true}]);
[
    {a: 30, b: 10, c: 20},
    {a: 20, b: 10, c: 30},
    {a: 10, b: 20, c: 30},
]

sortObjectList(objs, [{by: 'b', desc: true}, {by: 'c'}]);
[
    {a: 10, b: 20, c: 30},
    {a: 30, b: 10, c: 20},
    {a: 20, b: 10, c: 30},
]

另一个例子:

var objs = [
    {a: 5, b: 5},
    {a: 10, b: 15},
    {a: 15, b: 25},
    {b: 10},
    {b: 20},
    {a: 10, b: 30},
    {a: 10, b: 12},
];

sortObjectList(objs, [{by: 'a'}, {by: 'b'}]);
[
    {a: 5, b: 5},
    {b: 10},
    {a: 10, b: 12},
    {a: 10, b: 15},
    {b: 20},
    {a: 10, b: 30},
    {a: 15, b: 25},
]
13赞 cbdeveloper 12/20/2019 #43

这是我对此的看法:

该参数是可选的,默认为“ASC”,表示升序。order

它适用于重音字符,并且不区分大小写。

注意:它对原始数组进行排序并返回。

function sanitizeToSort(str) {
  return str
    .normalize('NFD')                   // Remove accented and diacritics
    .replace(/[\u0300-\u036f]/g, '')    // Remove accented and diacritics
    .toLowerCase()                      // Sort will be case insensitive
  ;
}

function sortByProperty(arr, property, order="ASC") {
  arr.forEach((item) => item.tempProp = sanitizeToSort(item[property]));
  arr.sort((a, b) => order === "ASC" ?
      a.tempProp > b.tempProp ?  1 : a.tempProp < b.tempProp ? -1 : 0
    : a.tempProp > b.tempProp ? -1 : a.tempProp < b.tempProp ?  1 : 0
  );
  arr.forEach((item) => delete item.tempProp);
  return arr;
}

片段

function sanitizeToSort(str) {
  return str
    .normalize('NFD')                   // Remove accented characters
    .replace(/[\u0300-\u036f]/g, '')    // Remove diacritics
    .toLowerCase()
  ;
}

function sortByProperty(arr, property, order="ASC") {
  arr.forEach((item) => item.tempProp = sanitizeToSort(item[property]));
  arr.sort((a, b) => order === "ASC" ?
      a.tempProp > b.tempProp ?  1 : a.tempProp < b.tempProp ? -1 : 0
    : a.tempProp > b.tempProp ? -1 : a.tempProp < b.tempProp ?  1 : 0
  );
  arr.forEach((item) => delete item.tempProp);
  return arr;
}

const rockStars = [
  { name: "Axl",
    lastname: "Rose" },
  { name: "Elthon",
    lastname: "John" },
  { name: "Paul",
    lastname: "McCartney" },
  { name: "Lou",
    lastname: "Reed" },
  { name: "freddie",             // Works on lower/upper case
    lastname: "mercury" },
  { name: "Ámy",                 // Works on accented characters too
    lastname: "winehouse"}

];

sortByProperty(rockStars, "name");

console.log("Ordered by name A-Z:");
rockStars.forEach((item) => console.log(item.name + " " + item.lastname));

sortByProperty(rockStars, "lastname", "DESC");

console.log("\nOrdered by lastname Z-A:");
rockStars.forEach((item) => console.log(item.lastname + ", " + item.name));

评论

0赞 Ankesh Pandey 8/27/2020
如果列表包含大写和小写字符组合的名称,则不起作用
0赞 cbdeveloper 9/7/2020
@AnkeshPandey 感谢您指出这一点。我已经修好了。
32赞 Abhishek 3/3/2020 #44

试试这个:

最高 ES5
// Ascending sort
items.sort(function (a, b) {
   return a.value - b.value;
});


// Descending sort
items.sort(function (a, b) {
   return b.value - a.value;
});
ES6 及更高版本中
// Ascending sort
items.sort((a, b) => a.value - b.value);

// Descending sort
items.sort((a, b) => b.value - a.value);

评论

2赞 Omar Hasan 3/16/2020
最佳和简单的解决方案
3赞 Thorvald 4/1/2022
对我不起作用,尝试了其他确实有效的解决方案,但这个不起作用。尝试按字符串排序。
0赞 1111161171159459134 8/15/2023
未正确传递负数
9赞 Nur 4/9/2020 #45

您可以使用可重用的排序函数。

Array.prototype.order = function (prop, methods = {}) {
    if (prop?.constructor == Object) {
        methods = prop;
        prop = null;
    }
    const [orderType_a, orderType_b] = methods.reverse ? [1, -1] : [-1, 1];

    const $ = x => prop
        ? methods.insensitive
            ? String(x[prop]).toLowerCase()
            : x[prop]
        : methods.insensitive
            ? String(x).toLowerCase()
            : x;

    const fn = (a, b) => $(a) < $(b) ? orderType_a : $(b) < $(a) ? orderType_b : 0;
    return this.sort(fn);
};

它可用于对数组和数组中的对象进行排序。

let items = [{ x: "Z" }, 3, "1", "0", 2, { x: "a" }, { x: 0 }];
items
    .order("x", { insensitive: 1 })
    // [ { x: 0 }, { x: 'a' }, 3, '1', '0', 2, { x: 'Z' } ]
    .order({ reverse: 1 })
    // [ { x: 0 }, { x: 'a' }, 3, 2, { x: 'Z' }, '1', '0' ]
    .sort(x => typeof x == "string" || typeof x == "number" ? -1 : 0)
    // [ '0', '1', 2, 3, { x: 0 }, { x: 'a' }, { x: 'Z' } ]

第一个(可选)>对数组中包含的对象进行排序。
第二是方法
> { reverse: any, insensitive: any }

3赞 Kamil Kiełczewski 6/11/2020 #46

基于这个优秀的教程,我想发展 Vlad Bezden 的答案,并解释为什么 localeCompare 比标准比较方法更好,比如 .让我们运行这个例子:strA > strB

console.log( 'Österreich' > 'Zealand' );  // We expect false
console.log( 'a' > 'Z' );                 // We expect false

原因是在 JavaScript 中,所有字符串都使用 UTF-16

let str = '';

// Order of characters in JavaScript
for (let i = 65; i <= 220; i++) {
  str += String.fromCodePoint(i); // Code to character
}

console.log(str);

大写字母先走(有小代码),然后是小写字母,然后是字符(之后)。这就是我们在第一个代码片段中得到 true 的原因 - 因为运算符比较字符代码。Öz>

正如你所看到的,比较不同语言的字符是一项艰巨的任务 - 但幸运的是,现代浏览器支持国际化标准ECMA-402。因此,在 JavaScript 中,我们有 which 来完成这项工作(means is less ; 1 means 相反; 0 means equal)strA.localeCompare(strB)-1strAstrB

console.log( 'Österreich'.localeCompare('Zealand') ); // We expect -1
console.log( 'a'.localeCompare('Z') );                // We expect -1

我想补充一点,它支持两个参数:语言和附加规则localeCompare

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

objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom,'en',{sensitivity:'case'}))

console.log(objs);

// in '>' comparison 'Jamf' will NOT be next to 'jamf'

7赞 SeyyedKhandon 12/4/2020 #47

简单回答:

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

详:

今天很简单,你可以将字符串与 .正如 Mozilla Doc 所说:localeCompare

该方法返回一个数字,指示 引用字符串为 、 或 或 。localeCompare()beforeafteris the same as the given string in sort order

    //example1:
    console.log("aaa".localeCompare("aab")); //-1
    console.log("aaa".localeCompare("aaa")); //0
    console.log("aab".localeCompare("aaa")); //1

    //example2:
    const a = 'réservé'; // with accents, lowercase
    const b = 'RESERVE'; // no accents, uppercase

    console.log(a.localeCompare(b));
    // expected output: 1
    console.log(a.localeCompare(b, 'en', { sensitivity: 'base' }));
    // expected output: 0

有关详细信息,请参阅 Mozilla 文档localeCompare

2赞 Marinos An 1/28/2021 #48

对于 fp-holics:

const objectSorter = (p) => (a, b) => ((a, b) => a>b ? 1 : a<b ? -1 : 0)(a[p], b[p]);
objs.sort(objectSorter('first_nom'));
30赞 Satish Chandra Gupta 2/3/2021 #49

使用 JavaScript 方法sort

可以使用比较函数修改 sort 方法,以对数字、字符串甚至对象数组等任何内容进行排序。

compare 函数作为可选参数传递给 sort 方法。

此比较函数接受 2 个参数,通常称为 ab。基于这 2 个参数,您可以修改排序方法以根据需要工作。

  1. 如果 compare 函数返回的分数小于 0,则该方法将 a 排序为低于 b 的索引。简单地说,a 将出现在 b 之前。sort()
  2. 如果 compare 函数返回等于 0,则该方法将元素位置保持原样。sort()
  3. 如果 compare 函数返回大于 0,则该方法在索引处对 a 进行排序,索引大于 b。只是 a 会在 b 之后出现。sort()

使用上述概念应用于对象,其中 a 将是对象属性。

var objs = [
  { first_nom: 'Lazslo', last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine' },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];
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);
console.log(objs)
// for better look use console.table(objs)
output

5赞 Wallace Sidhrée 3/19/2021 #50

我一直在各种项目中使用此实用程序,效果很好。它也是非常模块化的:

  • 传递要排序的键的名称
  • 选择排序是升序还是

sortArrayOfObjsByKeyUtil.js

// Sort array of objects by key
// ------------------------------------------------------------
const sortArrayOfObjsByKey = (array, key, ascdesc) =>
  array.sort((a, b) => {
    const x = a[key];
    const y = b[key];
    if (ascdesc === 'asc') {
      return x < y ? -1 : x > y ? 1 : 0;
    }
    if (ascdesc === 'desc') {
      return x > y ? -1 : x < y ? 1 : 0;
    }
    return null;
  });

sortArrayOfObjsByKeyUtil.test.js

import sortArrayOfObjsByKey from './sortArrayOfObjsByKeyUtil';

const unsortedArray = [
  {
    _id: '3df55221-ce5c-4147-8e14-32effede6133',
    title: 'Netlife Design',
    address: {
      PostalAddress: {
        streetAddress: 'Youngstorget 3',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0181',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.914322, lng: 10.749272 },
  },
  {
    _id: 'cd00459f-3755-49f1-8847-66591ef935b2',
    title: 'Home',
    address: {
      PostalAddress: {
        streetAddress: 'Stockfleths gate 58A',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0461',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.937316, lng: 10.751862 },
  },
];

const sortedArray = [
  {
    _id: 'cd00459f-3755-49f1-8847-66591ef935b2',
    title: 'Home',
    address: {
      PostalAddress: {
        streetAddress: 'Stockfleths gate 58A',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0461',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.937316, lng: 10.751862 },
  },
  {
    _id: '3df55221-ce5c-4147-8e14-32effede6133',
    title: 'Netlife Design',
    address: {
      PostalAddress: {
        streetAddress: 'Youngstorget 3',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0181',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.914322, lng: 10.749272 },
  },
];

describe('sortArrayOfObjsByKey', () => {
  it(`sort array by 'title' key, ascending`, () => {
    const testInput = sortArrayOfObjsByKey(unsortedArray, 'title', 'asc');
    const testOutput = sortedArray;
    expect(testInput).toEqual(testOutput);
  });
});

27赞 artem 4/9/2021 #51

编写短代码:

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

评论

1赞 Someone Special 4/15/2021
如果值相等怎么办?考虑到您可以返回 3 个值 -1, -1, 0
0赞 artem 4/15/2021
@SomeoneSpecial那又怎样?结果是一样的
0赞 Kaleem Elahi 6/27/2021
1 ||-1 表示 ?
0赞 Robert Talada 11/11/2021
@KaleemElahi如果我理解正确的话,他把它当作一个位面具。如果a.last_nom > b.last_nom则 1 ELSE -1。根据比较有效地向上或向下移动项目。
1赞 artem 11/11/2021
没有位掩码,表达式等于 ,运算符返回第一个逻辑值,运算符返回第一个逻辑值。a>b && 1|| -1a> b ? 1 : -1&&false||true
1赞 Force Bolt 5/29/2021 #52

试试这个方法:

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

const compareBylastNom = (a, b) => {
    // Converting to uppercase to have case-insensitive comparison
    const name1 = a.last_nom.toUpperCase();
    const name2 = b.last_nom.toUpperCase();

    let comparison = 0;

    if (name1 > name2) {
        comparison = 1;
    } else if (name1 < name2) {
        comparison = -1;
    }
    return comparison;
}

console.log(objs.sort(compareBylastNom));
143赞 muasif80 6/16/2021 #53

区分大小写

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

不区分大小写

arr.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1);

实用笔记

如果顺序没有更改(在相同的字符串的情况下),则条件将失败并返回。但是,如果字符串相同,则返回 1 或 -1 将导致正确的输出>-1

另一种选择可能是使用运算符而不是>=>


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


// Define a couple of sorting callback functions, one with hardcoded sort key and the other with an argument sort key
const sorter1 = (a, b) => a.last_nom.toLowerCase() > b.last_nom.toLowerCase() ? 1 : -1;
const sorter2 = (sortBy) => (a, b) => a[sortBy].toLowerCase() > b[sortBy].toLowerCase() ? 1 : -1;

objs.sort(sorter1);
console.log("Using sorter1 - Hardcoded sort property last_name", objs);

objs.sort(sorter2('first_nom'));
console.log("Using sorter2 - passed param sortBy='first_nom'", objs);

objs.sort(sorter2('last_nom'));
console.log("Using sorter2 - passed param sortBy='last_nom'", objs);

评论

0赞 Gangula 10/30/2021
区分大小写的方法是很好的速记 - 特别是当值是数字或日期时。
0赞 Gangula 10/30/2021
提示:如果您想颠倒顺序,您可以简单地交换 和 例如:从 到-111 : -1-1 : 1
0赞 muasif80 10/31/2021
换:)怎么样(a, b) to (b, a)
2赞 Gangula 10/31/2021
是的,这也行得通。我只是发现交换更直接、更合乎逻辑。1-1
3赞 user3125367 12/23/2022
对于相等的项目返回非零违反了 compareFn 协定。该问题可能不会在当前的 sort() 实现中表现出来,但并非面向未来和/或可能会影响性能。
0赞 Rustam 1/15/2022 #54

我知道已经有很多答案,包括那些带有 localeCompare 的答案,但如果您出于某种原因不想/不能使用 localeCompare,我建议您使用此解决方案而不是三元运算符解决方案:

objects.sort((a, b) => (a.name > b.name) - (a.name < b.name));

有人可能会说这段代码在做什么并不明显,但在我看来,三元运算符更糟。如果一个三元运算符的可读性足够高,那么两个三元运算符一个嵌入到另一个运算符中——真的很难读,而且很丑陋。只有两个比较运算符和一个减号运算符的单行代码非常易于阅读,因此易于推理。

16赞 ccpizza 2/25/2022 #55

使用 Intl.Collator 对对象进行排序,以备特定情况下进行自然字符串排序(即 )。["1","2","10","11","111"]

const files = [
 {name: "1.mp3", size: 123},
 {name: "10.mp3", size: 456},
 {name: "100.mp3", size: 789},
 {name: "11.mp3", size: 123},
 {name: "111.mp3", size: 456},
 {name: "2.mp3", size: 789},
];

const naturalCollator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});

files.sort((a, b) => naturalCollator.compare(a.name, b.name));

console.log(files);

注意:构造函数参数 for 表示区域设置,可以是显式的 ISO 639-1 语言代码,例如 ,也可以是系统默认区域设置,当 .undefinedIntl.Collatorenundefined

浏览器对 Intl.Collator 的支持

评论

1赞 David Scott Kirby 3/3/2022
这是一种巧妙的方法。
6赞 DonCarleone 9/14/2022 #56
let propName = 'last_nom';

let sorted_obj = objs.sort((a,b) => {
    if(a[propName] > b[propName]) {
        return 1;
    }
    if (a[propName] < b[propName]) {
        return -1;
    }
    return 0;
}

//This works because the js built-in sort function allows us to define our
//own way of sorting, this funny looking function is simply telling `sort` how to
//determine what is larger. 
//We can use `if(a[propName] > b[propName])` because string comparison is already built into JS
//if you try console.log('a' > 'z' ? 'a' : 'z')
//the output will be 'z' as 'a' is not greater than 'z'
//The return values 0,-1,1 are how we tell JS what to sort on. We're sorting on the last_nom property of the object. 
//When sorting a list it comes down to comparing two items and how to determine which one of them is "larger". 
//We need a way to tell JS how to determine which one is larger. 
//The sort defining function will use the case that returns a 1 to mean that a > b
//and the case that returns -1 to mean that a < b

评论

1赞 stuckoverflow 11/22/2022
您能简要描述一下返回值 1、-1、0 吗?
1赞 DonCarleone 11/23/2022
这就是我们告诉 JS 要排序的方式。我们正在对对象的属性进行排序。在对列表进行排序时,归根结底是比较两个项目以及如何确定其中哪一个“更大”。我们需要一种方法来告诉 JS 如何确定哪个更大。排序定义函数将使用返回 1 的情况表示 > b,返回 -1 的情况表示 a < b。last_nom
1赞 Peter Mortensen 12/11/2022
您可以将其添加到答案中吗(评论可能随时删除)?但是 ********************** 没有 ************************** “编辑:”、“更新:”或类似内容 - 答案应该看起来像今天写的一样。
0赞 Gerold Broser 6/11/2023
@stuckoverflow 参见 Intl.Collator.prototype.compare() > 描述:“比较 getter 函数返回一个数字,指示 string1 和 string2 如何根据此 Intl.Collator 对象的排序顺序相互比较:如果 string1 位于 string2 之前,则为负值; 如果 string1 位于 string2 之后,则为正值;如果它们被认为是相等的,则为 0。
1赞 Tarik Al Mashni 12/2/2022 #57

我会这样做:

[...objs].sort((a, b) => a.last_nom.localeCompare(b.last_nom))
0赞 Zia 4/18/2023 #58

我喜欢下面。

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

objs.sort(function(a, b) {
  const nameA = a.name.toUpperCase(); // ignore upper and lowercase
  const nameB = b.name.toUpperCase(); // ignore upper and lowercase
  if (nameA < nameB) {
    return -1;
  }
  if (nameA > nameB) {
    return 1;
  }
  // names must be equal
  return 0;
});

console.log(arr);
1赞 Avnish Jayaswal 6/3/2023 #59
  var objs = [ 
    { firstName: 'A', lastName: 'Mark'  }, // b
    { firstName: 'E', lastName: 'askavy' }, // a
    { firstName: 'C', lastName: 'peter' }
];

objs.sort((a,b) => {
   return a.firstName.localeCompare(b.firstName) // Sort Ascending 
}) 

objs.sort((a,b) => {
   return b.firstName.localeCompare(a.firstName) // Sort Decending
}) 

 console.log(objs)
1赞 Muhammad Shoaib Riaz 8/18/2023 #60

您还可以添加一个通用函数,用于按升序或降序对字符串和数字进行排序,例如:

function sortArray({ data, key, sortingOrder }) {
    return data.sort((a, b) => {
      const firstValue = typeof a[key] === 'string' ? a[key]?.toLowerCase() : a[key];
      const secondValue = typeof b[key] === 'string' ? b[key]?.toLowerCase() : b[key];

      if (firstValue < secondValue) {
        return sortingOrder === SORT_ORDER.ASC ? -1 : 1;
      }
      if (firstValue > secondValue) {
        return sortingOrder === SORT_ORDER.ASC ? 1 : -1;
      }
      return 0;
    });
  }



const SORT_ORDER={
DES: 'Z-A',
ASC: 'A-Z'
};

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Zwalle'     },
    { first_nom: 'Pig',    last_nom: 'Podine'   },
    { first_nom: 'Pirate', last_nom: 'Antun' }
];

const sortedArray = sortArray({
data: objs,
key: 'last_nom',
sortingOrder: SORT_ORDER.ASC
});

console.log('sorted array', sortedArray);

0赞 DanCZ 9/15/2023 #61
function compareProperty({ key, direction }) {
    return function (a, b) {
        const ap = a[key] || ''
        const bp = b[key] || ''

        return (direction === "desc" ? -1 : 1) * ((typeof ap === "string" && typeof bp === "string") ? ap.localeCompare(bp) : ap - bp)
    }
}

使用 null、未定义的键。数字、日期、字符串、带有变音符号的字符按预期排序。

用:

const sort = {
    key: "name",
    direction: "asc"
}

results.toSorted(compareProperty(sort))