如何sorting一个JavaScript对象,或将其转换为数组?
我有一些从服务器获取的JSON数据。 在我的JavaScript中,我想对它做一些sorting。 我认为sort()函数将做我想要的。
但是,JavaScript似乎在到达时立即将JSON数据转换为Object。 如果我尝试使用sort()方法,我会遇到很多错误(使用Firebug进行testing)。
我查看了networking,每个人似乎都说,一方面,JSON对象已经是JavaScript数组,并且对象也可以像数组一样对待。 就像这个问题一样 ,在一个答案中,一个人说:“[Object object]是你的数据 – 你可以像访问数组一样访问它。
但是,这不完全正确。 JavaScript不会让我在我的对象上使用sort()。 而且由于默认的假设是它们都是相同的东西,所以似乎没有任何关于如何将Object转换为Array的指示,或者强制JavaScript将它当作一个对象,或者类似的东西。
所以…我如何获得JavaScript,让我把这个数据作为一个数组和sorting()呢?
我的对象的控制台日志输出如下所示(我希望能够按照“级别”中的值进行sorting):
OBJECT JSON数据
{ 1: { displayName: "Dude1", email: "dude1@example.com<mailto:dude1@example.com>", lastActive: 1296980700, level: 57, timeout: 12969932837 }, 2: { displayName: "Dude2", email: "dude2@example.com<mailto:dude2@example.com>", lastActive: 1296983456, level: 28, timeout: 12969937382 }, 3: { displayName: "Dude3", email: "dude3@example.com<mailto:dude3@example.com>", lastActive: 1296980749, level: 99, timeout: 129699323459 } }
Array.prototype.slice.call(arrayLikeObject)
是将数组types的对象转换为数组的标准方法。
这只适用于arguments
对象。 将一个通用对象转换成一个数组有点痛苦。 这是来自underscore.js的源代码:
_.toArray = function(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); if (_.isArray(iterable)) return iterable; if (_.isArguments(iterable)) return slice.call(iterable); return _.values(iterable); }; _.values = function(obj) { return _.map(obj, _.identity); };
原来,你将需要遍历你的对象,并将其映射到一个数组。
var newArray = [] for (var key in object) { newArray.push(key); }
你混淆了数组和“关联数组”的概念。 在JavaScript中,由于可以以格式object["key"]
访问数据,所以对象的types就像关联数组一样。 它们不是真正的关联数组,因为对象是无序列表。
对象和数组是非常不同的。
使用下划线的例子:
var sortedObject = _.sortBy(object, function(val, key, object) { // return an number to index it by. then it is sorted from smallest to largest number return val; });
看到现场的例子
你应该能够将一个JavaScript对象转换成一个像这样的数组…
var obj = { '1': 'a', '2': 'b', '3': 'c' }; var arr = []; for (var key in obj) { if (obj.hasOwnProperty(key)) { arr.push(obj[key]); } } console.log(arr); // ["a", "b", "c"]
在jsFiddle上看到它 。
如果你的JavaScript对象是一个类似数组的对象 ,也就是具有有效数字length
属性的对象实例,那么你可以直接使用许多本地数组方法,这要归功于call
方法。 例如:
// Sorts the given objet in-place as if it was an array Array.prototype.sort.call(yourObject);
所以,如果你知道要sorting的条目数( 如何有效地计算JavaScript中的对象的键/属性数量? ),你可以:
yourObject.length = theNumberOfEntries; Array.prototype.sort.call(yourObject); // Optionally: delete yourObject.length;
请注意,这将只对按“0”,“1”,“2”,…指定length - 1
属性进行sorting,就像在数组中一样。 该对象的其他属性将不会被重新sorting。
这些答案大多过度复杂的问题或使用JQuery或Underscore而OP从来没有要求这些。
你可以像下面这样将一个对象转换成一个数组:
myArray= Object.keys(data).map(function(key) { return data[key] });
并像这样sorting结果:
myArray.sort(function(x, y) {return x.level - y.level});
如果你需要id / index,那么你需要做更多的事情:
Object.keys(data).map(function(key) { var obj = data[key]; obj.index = key; return obj });
我最近偶然发现了这个问题,同时试图用它的一个属性对一个对象数组进行分组,结果导致一个对象因此我不能sorting。
具体来说,这是一个我想按年分组的博客post,并按年份sorting。 我使用了下划线的效用:
var grouped = _.groupBy(blogposts, function(post){ var date = new Date(post.publication_date) return date.getFullYear() }) //=> { 2010: [blogpost, blogpost,etc], 2011: [blogpost, etc] }
正如@Raynos所解释的,在sorting之前,我必须首先得到某种数组。
事实certificate,下划线(1.4)有一个很好用的小工具,它将把对象的{key:value}映射到[key,value]的数组中。 相当于:
var paired = _.map(grouped, function(val, key){ return [key, val] }) //=> [ [2010, [blogpost, blogpost, ...] ], [2011, [blogpost, blogpost, ...]]...]
从那里你可以很容易地sorting每对的第一个任期。
最终结果如下:
var grouped = _.groupBy(result.resource, function(resource){ var date = new Date(resource.pub_date) return date.getFullYear() //+ "." + (date.getMonth()+1) }) var paired = _.pairs(grouped) var sorted = _.sortBy(paired, function(pairs){ return -parseInt(pairs[0]) }) return sorted; // Giving me the expected result: //=> [ [2013, [blogpost, blogpost, ...] ], [2012, [blogpost, blogpost, ...]]...]
我敢肯定,虽然有一个更好,更高性能的方式,但来自ruby这个代码是立即可以理解的我。
jQuery提供了一个map函数,它将遍历数组或对象中的每个元素,并将结果映射到一个新的数组中。
在jQuery 1.6之前,$ .map()仅支持遍历数组。
我们可以使用这个将任何对象转换为数组,如下所示…
myArray = $.map(myObject, function (el) { return el; });
但是…如果callback函数返回null或未定义 ,那么该值将从数组中移除 ,在大多数情况下,这是有用的,但是如果在myArray中需要空值,则会导致问题。
jQuery为此提供了一个解决scheme…以单值返回值作为数组
myArrayWithNulls = jQuery.map(myObject, function (el) { return [el]; });
这里有一个小提琴展示了两种方法: http : //jsfiddle.net/chim/nFyPE/
我写了一个小函数recursion转换对象的属性也可能是对象到multidimensional array。 这段代码依赖于forEach和toArray方法的下划线或lodash。
function deepToArray(obj) { var copy = []; var i = 0; if (obj.constructor == Object || obj.constructor == Array) { _.forEach(obj, process); } else { copy = obj; } function process(current, index, collection) { var processed = null; if (current.constructor != Object && current.constructor != Array) { processed = current; } else { processed = deepToArray(_.toArray(current)); } copy.push(processed); } return copy; }
这里是小提琴: http : //jsfiddle.net/gGT2D/
注意:这是为了将原本是数组的对象转换回数组而被写入的,所以任何非数组索引键值都将丢失。