我有一个JavaScript对象数组:

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

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

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


当前回答

所以这里有一种排序算法,它可以在任何类型的对象数组中按任何顺序排序,而不受数据类型比较的限制(如Number、String等):

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,则返回降序。

其他回答

排序(更多)复杂的对象阵列

由于您可能会遇到类似于此阵列的更复杂的数据结构,因此我将扩展解决方案。

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

Goal

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

障碍

现在,在基本解决方案中,使用括号表示法来计算要动态排序的财产。不过,在这里,我们还必须动态地构造括号表示法,因为您可能会期望像People['Name.Name']这样的符号会起作用,但这不起作用。

另一方面,简单地做人物['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://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的工作示例

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

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

在JSFiddle中尝试此示例。

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

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

按KeyUtil.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;
  });

按KeyUtil.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);
  });
});

一个简单的方法:

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

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

此排序功能可用于所有对象排序:

对象deepObject(深度对象)数字数组

您还可以通过传递1,-1作为参数进行升序或降序排序。

Object.defineProperty(Object.prototype,'deepVal'{可枚举:false,可写:true,值:函数(propertyChain){var level=propertyChain.split('.');父项=此项;对于(var i=0;i<levels.length;i++){if(!parent[levels[i]])返回未定义;parent=父[级别[i]];}返回父项;}});函数dynamicSortAll(属性,sortOrders=1){/**默认排序为升序。如果你需要按降序排序传递-1作为参数**/var sortOrder=sortOrders;返回函数(a,b){var result=(属性?((a.deepVal(属性)>b.deepVal(属性))?1:(a.deepVal(属性)<b.deepVal(属性))-1:0):((a>b)?1:(a<b)-1 : 0))返回结果*sortOrder;}}深度对象=[{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(deepojResult))变量obj=[{first_nom:'Lazslo',last_nom:'Jamf'},{first_nom:'猪',last_nom:'Bodine'},{first_nom:'海盗',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))