使用Javascript和Underscore尝试通过对象属性对{key: object}对进行排序

3
{
  "TR":{
    "total_fans":1848,
    "country_name":"Turkey"
  },
  "US":{
    "total_fans":1097,
    "country_name":"United States"
  },
  "DE":{
    "total_fans":915,
    "country_name":"Germany"
  },
  "MX":{
    "total_fans":1148,
    "country_name":"Mexico"
  },
  "RS":{
    "total_fans":359,
    "country_name":"Serbia"
  },
  "IT":{
    "total_fans":798,
    "country_name":"Italy"
  }
}

我希望能够按照粉丝数量对此进行排序。例如,在这种情况下,应该使用JS和Underscore按照“TR”,“MX”,“US”等顺序进行排序...如果有帮助的话。 谢谢!

您的对象出现语法错误...是整个对象吗? - Brad
我编辑了一下,可能弄乱了什么,但好像Doorknob已经修好了。在stackoverflow上有没有一种格式化的方法,而不只是用空格? - natecraft1
5个回答

4

JavaScript对象是无序的,所以您将无法排序或以其他方式定义特定顺序。

您可以将属性转换为数组,然后对其进行排序,但这就是您能得到的。

由于您似乎想按粉丝数量排序,因此可以这样做。

Object.keys(myObject)
    .sort(function(a,b) {
        return myObject[a].total_fans - myObject[b].total_fans;
    }).forEach(function(key) {
        console.log(myObject[key]);
    });

为了支持IE8及以下版本,您需要为Object.keysArray.prototype.forEach打补丁。
正如Bruce Lim所指出的,这是一个升序排序。要降序,请在return后交换-运算符的操作数。
return myObject[b].total_fans - myObject[a].total_fans;

他实际上想按粉丝排序。 - tckmn
2
@natecraft1 把属性改成了 total_fans。它可以按升序排序。要按降序排序:返回 myObject[b].total_fans - myObject[a].total_fans; - Bruce Lim
哇,干得好饼干怪兽!我完全忘记了Object.keys...它恰好完成了我自己尝试使用Object.ownProps的操作,但是Object.keys更标准化。你的回答显然是最佳的。 - Ethan Brown
@EthanBrown:谢谢! :-) - cookie monster
嘿,Cookie,好东西。你会给这个问题起什么名字,以便大多数遇到相同问题的人都能找到它?我还在学习这个行话 ;) - natecraft1
@natecraft1: 我认为你的标题非常描述你所要求的内容。也许使用key:value对而不是key:object对会更好,但除此之外,你已经掌握了这个术语。也许你注意到了,我没有使用underscore中的forEach,但它是相同的,只需要将排序后的数组作为第一个参数传递即可 :) - cookie monster

1

尝试使用数组进行排序:

var array = [];

// copy object to array
for (var x in yourObject) array.push([x, yourObject[x].total_fans]);

// sort array
array.sort(function(item1, item2) { return item1[1] - item2[1] });

// now get the keys
var keys = [];
for (var i = 0; i < array.length; i ++) keys.push(array[i][0]);

// keys = ["RS", "IT", "DE", "US", "MX", "TR"]

请注意,如果您不关心旧版IE浏览器,使用map可以更轻松地获取密钥。

1
如果您不关心IE < 9,那么不需要使用下划线。假设您的结构在变量obj中:
var sorted = Object
   .keys(obj)
   .map(function(key) {
       // Put the country in the item?
       obj[key].country = key;
       return obj[key];
   })
   .sort(function(a, b) {
       if (a.total_fans > b.total_fans) {
           return -1;
       } else if (b.total_fans > a.total_fans) {
           return 1;
       }
       return 0;
   });

这将为您提供一个已排序的数组,其中拥有最多粉丝的项目排在首位,并为每个项目添加国家代码(如果需要可以省略)。

Jacob感谢您的回答,我从中学到了很多。 - natecraft1

1
更新:在与Doorknob的激烈但有用的交流中,我意识到他关于谨慎修改Object.prototype的观点非常好。我修改了答案,使得Object.prototype的扩展不那么侵入性,通过使新方法不可枚举来实现。谢谢,Doorknob!
更新2:我现在意识到OP明智地选择了正确的答案。Object.keys正好做了我的ownProps方法(见下文)所做的事情,并且它是一个标准的方法(尽管你仍然需要在IE8中使用polyfill)。我会删除这个答案,因为cookie monster把它解决了,但我认为这是一个有用的讨论,即使ownPropsObject.keys是多余的,它可能会教给某人...一些东西。
我写了一个方便的函数叫做ownProps,它返回一个对象的所有属性名称(不包括原型链中的属性)。这是一种更加函数化的方式来做Doorknob上面建议的事情:
// retrieves all of the properties of an object as an array, 
// omitting properties in the prototype chain; note that we use
// Object.defineProperty so we can make this non-enumerable, thereby
// making a safer modification of Object.prototype
Object.defineProperty(Object.prototype,'ownProps',{
  enumerable: false,
  value: function() {
    var props = []; for( var prop in this ) { 
        if( this.hasOwnProperty( prop ) ) props.push( prop ); 
    } 
    return props;
  }
});

有了这个,您可以使用自定义排序函数对对象进行排序:

var obj = {"TR":{"fans":1848,"country_name":"Turkey"}/*...*/}

var sortedKeys = obj.ownProps().sort(function(a,b){
    return obj[a].fans - obj[b].fans;
});

不同意,门把手。JavaScript 的美妙之处之一。并非 Douglas Crockford 所说的一切都是金子般闪耀的。 - Ethan Brown
1
好的,假设有人这样写代码 if (someVariable.ownProps === undefined) someVariable.ownProps = ['some', 'stuff']。糟糕,你的代码刚刚出了问题 :( - tckmn
与您所做的任何其他事情相反?如果我创建了一个不在Object.prototype上的自定义函数来执行该操作呢?有人可能会覆盖它。 - Ethan Brown
在JavaScript中,有很多机会搞砸事情...这是它本质的一部分。虽然我不会为了你提出的好理由而随意修改Object.prototype,但一些恰当和明智的扩展并不是世界末日。 - Ethan Brown
2
就我个人而言,我完全同意这句话:“并非道格拉斯·克罗克福德所说的一切都是金子般珍贵的。” ;-D - cookie monster
显示剩余7条评论

-1

解决方案:http://jsfiddle.net/az7XN/

假设你的粉丝对象是一个fansObj

for(prop in fansObj){
   console.log(prop, fansObj[prop]);
}

输出示例:TR,{"fans": 1848,"country_name":"土耳其"}

for 循环之前声明数组变量,并将每个对象推入其中:

var arr = [];
for(prop in fansObj){
   console.log(prop, fansObj[prop]);
   arr.push(fansObj[prop]);
}

然后排序:

arr.sort(function(a,b){parseInt(b['total_fans'],10) - parseInt(a['total_fans'])});

parseInt(obj,10)会将对象转换为十进制整数。

现在你有一个已排序的数组(根据sort函数内部的比较条件(a-b=desc或b-a=asc))

使用的函数:

for..in

Array.prototype.sort()

parseInt()

的翻译内容为:

更新:添加了排序。首先我写了如何遍历对象中的所有属性,然后添加了排序。 - Epsil0neR
不需要使用 parseInt... total_fans 属性已经是一个数字了。 - Ethan Brown
@EthanBrown 是的,你说得对,但我以为那是 JSON 里的字符串,所以我加了解析。最好还是有整数解析器,因为在 JavaScript 中你可以将任何东西设置为 total_fans - Epsil0neR

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