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

4095
我有一个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()方法吗?

2
大小写敏感或不敏感排序? - Peter Mortensen
61个回答

5

对我而言,它有效。这里会将undefined保留到最后。

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


5

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

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

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


4
使用LodashUnderscore.js,这很简单:
const sortedList = _.orderBy(objs, [last_nom], [asc]); // Ascending or descending

3

我刚刚增强了 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;
    }
});

并且修改了_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上查看完整脚本。


3

在使用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

这个排序函数可以用于所有对象排序:

  • 对象
  • 深度对象
  • 数字数组

您也可以通过将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))


3

深度

基于这篇优秀的教程,我想要完善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);

大写字母排在前面(代码更小),其次是小写字母,然后是字符Ö(在z之后)。这就是为什么我们在第一个片段中得到了true的原因 - 因为运算符>比较字符代码。

如您所见,在不同语言中比较字符是一项非常复杂的任务 - 幸运的是,现代浏览器支持国际化标准ECMA-402。所以在JavaScript中,我们有strA.localeCompare(strB) 来完成此任务(-1表示strA小于strB;1表示相反;0表示相等)。

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'


2
我遇到了一个问题,需要对对象数组进行排序,并改变值的优先级。基本上,我想通过他们的年龄来排序人员数组,然后按姓氏排序 - 或仅按姓氏、名字排序。
我认为这是与其他答案相比最简单的解决方案。
调用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
HTML是虚假的。head元素在html元素之外。其余的答案也是虚假的吗? - Peter Mortensen

2
对于喜欢 fp 的人:
const objectSorter = (p) => (a, b) => ((a, b) => a>b ? 1 : a<b ? -1 : 0)(a[p], b[p]);
objs.sort(objectSorter('first_nom'));

2

以下是一种排序算法,可以按照任何顺序对任何类型的对象数组进行排序,而不受数据类型比较的限制(即数字、字符串等):

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 是你想要排序的对象的键,

  • reverse 是一个布尔参数,如果为 true,则结果为 升序,如果为 false,则结果为 降序


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