有没有一种方法可以对JavaScript对象中的键进行排序/排序?


75

例如以下

var data = {
    'States': ['NSW', 'VIC'],
    'Countries': ['GBR', 'AUS'],
    'Capitals': ['SYD', 'MEL']
}
for (var item in data) {
    console.log(item);
}

版画

States
Countries
Capitals

有没有一种方法可以按字母顺序排序以便打印

Capitals
Countries
States



Answers:


132

不在对象本身之内:对象的属性集合是无序的。

您可以做的一件事是使用Object.keys(),对Array进行排序,然后对其进行迭代。

Object.keys(data)
      .sort()
      .forEach(function(v, i) {
          console.log(v, data[v]);
       });

不支持ECMAScript 5th版本的浏览器的补丁(实现):


1
值得补充的是,如果您想颠倒排序顺序,可以将.sort()替换为.replace()。另外,sort()和reverse()接受比较函数作为参数,使您可以微调排序。w3schools.com/jsref/jsref_sort.asp
Charles Jaimet '16

4
@CharlesJaimet:不确定您的意思.replace()。你是说.reverse()吗 确实可以使用该功能,但前提是您希望颠倒当前顺序。如果要颠倒排序顺序,则必须先对其进行排序。该.sort()方法确实接受函数,但.reverse()不接受。

谢谢@squint。打字太快,思考太慢。:)
查尔斯·杰伊特

这解决了我的问题,但是我很想知道i函数(v,i)中的参数表示什么
William Carron

2
@WillCarron:这是当前迭代的数字索引。因此,如果有3个按键,在i将被赋予012在回调的每个相应的调用。因为i在函数中没有使用它,所以可以安全地删除它,因为JS从来不需要您为传递的所有或任何参数提供参数。使用浏览器中可用的日志记录功能,您可以检查应用程序中数据的值。console.log("The value of 'i' is:", i)

25

这是一个很好的功能解决方案:

基本上,

  1. 将密钥提取到列表中 Object.keys
  2. sort 按键
  3. 将列表缩小到一个对象以得到所需的结果

ES5解决方案:

not_sorted = {b: false, a: true};

sorted = Object.keys(not_sorted)
    .sort()
    .reduce(function (acc, key) { 
        acc[key] = not_sorted[key];
        return acc;
    }, {});

console.log(sorted) //{a: true, b: false}

ES6解决方案:

not_sorted = {b: false, a: true}

sorted = Object.keys(not_sorted)
    .sort()
    .reduce((acc, key) => ({
        ...acc, [key]: not_sorted[key]
    }), {})

console.log(sorted) //{a: true, b: false}

17

就在这里。不在ECMAScript标准之内,但在浏览器和Node.js中受支持,并且显然稳定。见https://stackoverflow.com/a/23202095/645715

编辑:这将返回一个对象,在其中按顺序排列键。您可以用来Object.keys(...)从对象中获取有序的密钥。

为什么要担心对象键顺序?在某些应用程序中,差异可能很重要,例如使用xml2js解析XML,后者将XML表示为嵌套对象,并使用XML标签作为哈希键。

有几点注意事项:

  • 看起来像整数的键会首先出现并按数字顺序显示。
  • 看起来像字符串的键会按插入顺序显示在旁边。
  • 此订单由 Object.keys(obj)
  • 报告的顺序for (var key in obj) {...}可能在Safari和Firefox中有所不同

该函数返回一个对象,该对象具有按字母顺序插入的已排序键:

function orderKeys(obj, expected) {

  var keys = Object.keys(obj).sort(function keyOrder(k1, k2) {
      if (k1 < k2) return -1;
      else if (k1 > k2) return +1;
      else return 0;
  });

  var i, after = {};
  for (i = 0; i < keys.length; i++) {
    after[keys[i]] = obj[keys[i]];
    delete obj[keys[i]];
  }

  for (i = 0; i < keys.length; i++) {
    obj[keys[i]] = after[keys[i]];
  }
  return obj;
}

这是一个快速测试:

var example = { 
      "3": "charlie",
      "p:style": "c",
      "berries": "e",
      "p:nvSpPr": "a",
      "p:txBody": "d",
      "apples": "e",
      "5": "eagle",
      "p:spPr": "b"
    }

var obj = orderKeys(example);

这回来

{ '3': 'charlie',
  '5': 'eagle',
  apples: 'e',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:spPr': 'b',
  'p:style': 'c',
  'p:txBody': 'd' }

然后,您可以按以下方式获得有序的密钥:

Object.keys(obj) 

哪个返回

["3", "5", "apples", "berries", "p:nvSpPr", "p:spPr", "p:style", "p:txBody"]

是的,谢谢。在类似这样的东西上效果很好:{2018-04-02 05:46:51:“ 0.0000003900”,2018-04-02 04:46:48:“ 0.0000004000”,2018-04-03 01:00:35:“ 0.0000004000“,2018-04-02 06:46:55:” 0.0000003900“,2018-04-02 02:46:34:” 0.0000004000“,…} 2018-04-02 01:46:25:” 0.0000003900“ 2018 -04-02 02:46:34:“ 0.0000004000” 2018-04-02 03:46:42:“ 0.0000003900” 2018-04-02 04:46:48:“ 0.0000004000” 2018-04-02 05:46: 51:“ 0.0000003900” 2018-04-02 06:46:55:“ 0.0000003900” 2018-04-03 00:00:32:“ 0.0000003900” 2018-04-03 01:00:35:“ 0.0000004000”原型:对象
雷·科伦

非常感谢。expected在这里做什么?没有提供时它不会抱怨。
Vael Victus '19

1
@VaelVictus很好,它是从单元测试中复制粘贴的,现在不需要。
原型

2

这是使用lodash对对象的键进行排序的单线

_.chain(obj).toPairs().sortBy(0).fromPairs().value()

用您的示例数据:

var data = {
    'States': ['NSW', 'VIC'],
    'Countries': ['GBR', 'AUS'],
    'Capitals': ['SYD', 'MEL']
}
data = _.chain(data)
  .toPairs() // turn the object into an array of [key, value] pairs
  .sortBy(0) // sort these pairs by index [0] which is [key]
  .fromPairs() // convert array of pairs back into an object {key: value}
  .value() // return value
/*
{
  Capitals: [ 'SYD', 'MEL' ],
  Countries: [ 'GBR', 'AUS' ],
  States: [ 'NSW', 'VIC' ]
}
*/


2

我会将其添加为@prototype的评论,但是我的代表不够高。

如果有人需要orderKeys@prototype编写的兼容版本eslint-config-airbnb

/**
 * Returns and modifies the input object so that its keys are returned in sorted
 * order when `Object.keys(obj)` is invoked
 *
 * @param {object} obj The object to have its keys sorted
 *
 * @returns {object} The inputted object with its keys in sorted order
 */
const orderKeys = (obj) => {
  // Complying with `no-param-reassign`, and JavaScript seems to assign by reference here
  const newObj = obj;
  // Default `.sort()` chained method seems to work for me
  const keys = Object.keys(newObj).sort();

  const after = {};
  // Add keys to `after` in sorted order of `obj`'s keys
  keys.forEach((key) => {
    after[key] = newObj[key];
    delete newObj[key];
  });

  // Add keys back to `obj` in sorted order
  keys.forEach((key) => {
    newObj[key] = after[key];
  });

  return newObj;
};

使用@prototype的测试:

const example = { 
  3: 'charlie',
  'p:style': 'c',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:txBody': 'd',
  apples: 'e',
  5: 'eagle',
  p:spPr: 'b'
}

const obj = orderKeys(example);

console.log(obj);

console.log(Object.keys(obj));

输出以下内容:

Babel Compiler v6.4.4
Copyright (c) 2014-2015 Sebastian McKenzie

{ 3: 'charlie',
  5: 'eagle',
  apples: 'e',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:spPr': 'b',
  'p:style': 'c',
  'p:txBody': 'd' }
[ '3',
  '5',
  'apples',
  'berries',
  'p:nvSpPr',
  'p:spPr',
  'p:style',
  'p:txBody' ]

无论值多少钱,我都需要在我的React应用程序中使用它,以便可以对基于state对象的下拉菜单进行排序,这些对象是在API响应后分配的。

最初我做了

return (
  // ...
  <Select
    options={Object.keys(obj).sort()}
    // ...
  />
  // ...
);

但是意识到该.sort()方法将在每次重新渲染时调用,因此需要@prototype的实现orderKeys

https://stackoverflow.com/users/645715/prototype


1

您也可以通过这种方式对其进行排序。

const data = {
  States: ['NSW', 'VIC'],
  Countries: ['GBR', 'AUS'],
  Capitals: ['SYD', 'MEL']
}

const sortedObject = Object.fromEntries(Object.entries(data).sort())

我无法详细解释它为什么有效,但显然它可以完美运行:)如果您不相信我,请尝试一下:D

请注意,您的浏览器或Node.js版本应支持 Object.fromEntries

有关浏览器的兼容性,请检查此页底部

对于Node,它将适用于12或更高版本。对于来自v1的Deno。


-3

如果转换为数组不适合您的模板,并且您知道对象的键,则还可以执行以下操作:

在您的控制器中,以正确的顺序定义一个带有键的数组:

this.displayOrder = [
    'firstKey',
    'secondKey',
    'thirdKey'
];

在模板中,重复displayOrder的键,然后使用ng-init引用回您的对象。

<div ng-repeat="key in ctrl.displayOrder" ng-init="entry = ctrl.object[key]">
     {{ entry.detail }}
</div>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.