如何在 JavaScript 中对对象集合进行排序,而不将其转换为数组

How to sort a collection of objects in JavaScript without converting it to an array

本文关键字:数组 转换 排序 JavaScript 集合 对象      更新时间:2023-09-26

我试图避免为以下用例编写自己的排序算法:

avatars = {};
avatars[102] = {userInfo: {buddy_name: 'Avatar102', is_online: 1}};
avatars[100] = {userInfo: {buddy_name: 'Avatar100', is_online: 1}};
avatars[101] = {userInfo: {buddy_name: 'Avatar101', is_online: 1}};
console.log(_.keys(avatars));
avatars = _.sortBy(avatars, function(avatar) {return avatar.userInfo.buddy_name.toLowerCase();});
console.log(_.keys(avatars));

下面是控制台输出:

  • ["102"、"100"、"101"]
  • ["0", "1", "2"]

如您所见,使用undescore的排序,我正在丢失关键数据。这个结构可能会变得非常大,所以我试图避免像转换为数组然后回到集合之类的事情。有没有办法在不滚动我自己的排序函数的情况下做到这一点?

你的avatars不是一个数组,它只是一个对象:

avatars = {};

因此,其元素没有定义的顺序:

未指定枚举属性的机制和顺序(第一个算法中的步骤 6.a,第二个算法中的步骤 7.a(。

和 15.2.3.7

(和 15.2.3.14(:

如果实现为 for-in 语句定义了特定的枚举顺序,则必须使用相同的枚举顺序来对此方法的步骤 3 中的列表元素进行排序。

您还可以查看第 8.6 节,查看是否提及对象中属性的顺序。对对象属性进行排序的唯一要求是,如果实现在任何地方定义了一个顺序,那么它必须在任何地方使用相同的顺序,但这是一个很大的如果。大多数实现可能对对象的键使用插入顺序,但我找不到任何需要它们的东西(如果有人可以指出规范中定义对象键的任何特定顺序的任何内容,我将不胜感激(。

也就是说,Underscore的sortBy基本上是一个Schwartzian Transform,结合了标准的JavaScript sort和Underscore的pluck来解开Schwartzian Transform备忘录包装器; pluck返回一个数组,因此sortBy也返回一个数组。因此,您的最终_.keys(avatars)调用实际上是在数组上调用_.keys;数组的键(AKA 可枚举属性(是数组的索引,这些索引是从零开始的连续整数。

您使用了错误的数据结构。如果你需要一个稀疏数组,但也需要像数组一样操作它(即排序(,那么你应该把索引放在对象里面,使用一个普通的数组和pluck而不是keys

var avatars = [
    {idx: 102, userInfo: {buddy_name: 'Avatar102', is_online: 1}},
    {idx: 100, userInfo: {buddy_name: 'Avatar100', is_online: 1}},
    {idx: 101, userInfo: {buddy_name: 'Avatar101', is_online: 1}}
];
console.log(_(avatars).pluck('idx'));
avatars = _(avatars).sortBy(function(avatar) {
    return avatar.userInfo.buddy_name.toLowerCase();
});
console.log(_(avatars).pluck('idx'));

演示:http://jsfiddle.net/ambiguous/UCWL2/

如果您还需要通过idx快速访问,则可以设置一个并行对象以进行直接idx访问:

var avatars_by_idx = { };
for(var i = 0; i < avatars.length; ++i)
    avatars_by_idx[avatars[i].idx] = avatars[i];

然后avatars_by_idx提供您正在寻找的直接访问权限。当然,您必须保持avatarsavatars_by_idx同步,但是如果您将它们都隐藏在对象后面,这并不是非常困难。