如何对Javascript对象进行排序,或将其转换为数组?

时间:2022-05-30 15:57:34

I have some JSON data that I get from a server. In my JavaScript, I want to do some sorting on it. I think the sort() function will do what I want.

我有一些从服务器获得的JSON数据。在JavaScript中,我想对它进行排序。我认为sort()函数会做我想做的事情。

However, it seems that JavaScript is converting the JSON data into an Object immediately on arrival. If I try to use the sort() method, I get errors a-plenty (using Firebug for testing).

然而,看起来JavaScript正在立即将JSON数据转换为对象。如果我尝试使用sort()方法,会得到大量错误(使用Firebug进行测试)。

I've looked around the net, and everyone seems to say that for one thing, JSON objects are already JavaScript arrays, and also that Objects can be treated just like arrays. Like over on this question, where in one of the answers, a guy says "The [Object object] is your data -- you can access it as you would an array."

我环顾了一下网络,似乎每个人都认为JSON对象已经是JavaScript数组,而且对象可以像数组一样被处理。就像在这个问题上一样,在其中一个答案中,一个人说“对象对象是你的数据——你可以像访问数组一样访问它。”

However, that is not exactly true. JavaScript won't let me use sort() on my object. And since the default assumption is that they're all the same thing, there don't seem to be any instructions anywhere on how to convert an Object to an Array, or force JavaScript to treat it as one, or anything like that.

然而,事实并非如此。JavaScript不允许我在对象上使用sort()。由于默认的假设是它们都是一样的,所以似乎没有任何指令说明如何将一个对象转换为数组,或强制JavaScript将其视为一个数组,或诸如此类的东西。

So... how do I get JavaScript to let me treat this data as an array and sort() it?

所以…如何让JavaScript让我将数据作为数组进行排序?

Console log output of my object looks like this (I want to be able to sort by the values in the "level"):

我的对象的控制台日志输出如下所示(我希望能够按“level”中的值进行排序):

OBJECT JSONdata

对象JSONdata

{ 
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
} 
}

7 个解决方案

#1


43  

Array.prototype.slice.call(arrayLikeObject)

Array.prototype.slice.call(arrayLikeObject)

is the standard way to convert and an array-like object to an array.

是转换和类数组对象到数组的标准方式。

That only really works for the arguments object. To convert a generic object to an array is a bit of a pain. Here's the source from underscore.js:

这只适用于参数对象。将泛型对象转换为数组有点麻烦。以下是来自underscore.com的消息来源:

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

Turns out you're going to need to loop over your object and map it to an array yourself.

事实证明,你需要对对象进行循环并将其映射到一个数组。

var newArray = []
for (var key in object) {
    newArray.push(key);
}

You're confusing the concepts of arrays and "associative arrays". In JavaScript, objects kind of act like an associative array since you can access data in the format object["key"]. They're not real associative arrays since objects are unordered lists.

您混淆了数组和“关联数组”的概念。在JavaScript中,对象有点像关联数组,因为您可以访问格式对象["key"]中的数据。它们不是真正的关联数组,因为对象是无序列表。

Objects and arrays are vastly different.

对象和数组有很大的不同。

An example of using underscore:

使用下划线的一个例子:

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

See live example

看到生活的例子

#2


7  

You should be able to convert a JavaScript object into an array like so...

您应该能够将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"]

See it on jsFiddle.

jsFiddle上看到它。

#3


6  

If your JavaScript object is an array-like object, that is, an Object instance with a valid numerical length property, then you can directly use many native Array methods on it thanks to the call method. For example:

如果您的JavaScript对象是一个类数组的对象,即具有有效数值长度属性的对象实例,那么由于调用方法,您可以直接在其上使用许多本机数组方法。例如:

// Sorts the given objet in-place as if it was an array
Array.prototype.sort.call(yourObject);

So if you know the number of entries to be sorted (How to efficiently count the number of keys/properties of an object in JavaScript?), you can do:

因此,如果您知道要排序的条目数量(如何有效地计算一个对象在JavaScript中的键/属性数量?),您可以这样做:

yourObject.length = theNumberOfEntries;
Array.prototype.sort.call(yourObject);
// Optionally: delete yourObject.length;

Note that this will only sort properties indexed by "0", "1", "2", ... to length - 1 inclusive, like in an Array. The object's other properties will not be re-ordered.

注意,这将只对索引为“0”、“1”、“2”、…长度- 1包含,如数组。对象的其他属性将不会被重新排序。

#4


4  

Most of these answers over-complicate the issue or use JQuery or Underscore whereas the OP never asked for those.

这些答案大多过于复杂,或者使用JQuery或下划线,而OP从未要求过这些。

You can convert an object to an array like this:

你可以将一个对象转换成这样的数组:

myArray= Object.keys(data).map(function(key) { return data[key] });

And sort the result like this:

将结果排序如下:

myArray.sort(function(x, y) {return x.level - y.level});

If you need the id/index, then you need to do a bit more:

如果您需要id/索引,那么您需要做更多:

Object.keys(data).map(function(key) { 
  var obj = data[key];
  obj.index = key;
  return obj 
});

#5


2  

I have stumbled upon that problem recently while trying to group an array of objects by one of it's properties, resulting in one object I could therefore not sort.

我最近偶然发现了这个问题,当时我试图根据一个对象的属性对一个对象数组进行分组,结果导致一个对象无法排序。

Concretely it's an array of blog posts I wanted to group by year and have them sorted by descending years. I used underscore's utility :

具体地说,这是我想按年分类的一系列博客文章,并按年递减排序。我使用了下划线的效用:

var grouped = _.groupBy(blogposts, function(post){
  var date = new Date(post.publication_date)
  return date.getFullYear()
})
//=> { 2010: [blogpost, blogpost,etc], 2011: [blogpost, etc] }

As @Raynos explained I had to end up with some sort of array first before sorting it...

正如@Raynos解释的那样,在排序之前,我必须先处理某种数组……

It turns out underscore (1.4) has a nice little utility called pairs which will map the {key: value} of your object in an array of [key, value]. The equivalent of :

结果显示,下划线(1.4)有一个很好的小实用程序,名为pair,它将在[key, value]数组中映射对象的{key: value}。相当于:

var paired = _.map(grouped, function(val, key){
  return [key, val]
})
//=> [ [2010, [blogpost, blogpost, ...] ], [2011, [blogpost, blogpost, ...]]...]

From there on you can easily sort by the first term of each pair.

从这里开始,你可以很容易地按每对的第一项排序。

Here's the end result:

最终的结果:

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, ...]]...]

I'm sure though there's a better and more performant way, but coming from ruby this code is immediately understandable for me.

我确信,虽然有更好、更高效的方法,但是从ruby中获得的这段代码对我来说是可以理解的。

#6


1  

jQuery offers a map function, which will iterate through each element in an array or object and map the results into a new array.

jQuery提供了一个map函数,它将遍历数组或对象中的每个元素,并将结果映射到一个新的数组中。

Prior to jQuery 1.6, $.map() supported traversing arrays only.

在jQuery 1.6之前,$.map()只支持遍历数组。

We can use this to convert any object to an array as follows...

我们可以使用它将任何对象转换为数组,如下所示……

  myArray = $.map(myObject, function (el) {
    return el;
  });

But... if the callback function returns null or undefined, then that value is removed from the array, in most cases this is useful, but it can cause problems if you need null values in myArray.

但是…如果回调函数返回null或undefined,那么该值将从数组中删除,在大多数情况下这是有用的,但如果在myArray中需要空值,则会导致问题。

jQuery offers a solution for this... return the value as an array with the single value

jQuery为此提供了一个解决方案……将值返回为具有单个值的数组。

myArrayWithNulls = jQuery.map(myObject, function (el) {
  return [el];
});

Here's a fiddle demonstrating the two approaches: http://jsfiddle.net/chim/nFyPE/

这是一个演示这两种方法的小提琴:http://jsfiddle.net/chim/nFyPE/。

http://jsperf.com/object-to-array-jquery-2

http://jsperf.com/object-to-array-jquery-2

#7


1  

I wrote a small function to recursively convert an object with properties that may also be objects to a multi-dimensional array. This code is dependent on underscore or lodash for the forEach and toArray methods.

我编写了一个小函数来递归地将具有属性的对象转换为多维数组。此代码依赖于forEach和toArray方法的下划线或破折号。

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

Here is the fiddle: http://jsfiddle.net/gGT2D/

这是小提琴:http://jsfiddle.net/gGT2D/

Note: This was written to convert an object that was originally an array back into an array, so any non-array index key values will be lost.

注意:这是为了将原来是数组的对象转换回数组,因此将丢失任何非数组索引键值。

#1


43  

Array.prototype.slice.call(arrayLikeObject)

Array.prototype.slice.call(arrayLikeObject)

is the standard way to convert and an array-like object to an array.

是转换和类数组对象到数组的标准方式。

That only really works for the arguments object. To convert a generic object to an array is a bit of a pain. Here's the source from underscore.js:

这只适用于参数对象。将泛型对象转换为数组有点麻烦。以下是来自underscore.com的消息来源:

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

Turns out you're going to need to loop over your object and map it to an array yourself.

事实证明,你需要对对象进行循环并将其映射到一个数组。

var newArray = []
for (var key in object) {
    newArray.push(key);
}

You're confusing the concepts of arrays and "associative arrays". In JavaScript, objects kind of act like an associative array since you can access data in the format object["key"]. They're not real associative arrays since objects are unordered lists.

您混淆了数组和“关联数组”的概念。在JavaScript中,对象有点像关联数组,因为您可以访问格式对象["key"]中的数据。它们不是真正的关联数组,因为对象是无序列表。

Objects and arrays are vastly different.

对象和数组有很大的不同。

An example of using underscore:

使用下划线的一个例子:

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

See live example

看到生活的例子

#2


7  

You should be able to convert a JavaScript object into an array like so...

您应该能够将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"]

See it on jsFiddle.

jsFiddle上看到它。

#3


6  

If your JavaScript object is an array-like object, that is, an Object instance with a valid numerical length property, then you can directly use many native Array methods on it thanks to the call method. For example:

如果您的JavaScript对象是一个类数组的对象,即具有有效数值长度属性的对象实例,那么由于调用方法,您可以直接在其上使用许多本机数组方法。例如:

// Sorts the given objet in-place as if it was an array
Array.prototype.sort.call(yourObject);

So if you know the number of entries to be sorted (How to efficiently count the number of keys/properties of an object in JavaScript?), you can do:

因此,如果您知道要排序的条目数量(如何有效地计算一个对象在JavaScript中的键/属性数量?),您可以这样做:

yourObject.length = theNumberOfEntries;
Array.prototype.sort.call(yourObject);
// Optionally: delete yourObject.length;

Note that this will only sort properties indexed by "0", "1", "2", ... to length - 1 inclusive, like in an Array. The object's other properties will not be re-ordered.

注意,这将只对索引为“0”、“1”、“2”、…长度- 1包含,如数组。对象的其他属性将不会被重新排序。

#4


4  

Most of these answers over-complicate the issue or use JQuery or Underscore whereas the OP never asked for those.

这些答案大多过于复杂,或者使用JQuery或下划线,而OP从未要求过这些。

You can convert an object to an array like this:

你可以将一个对象转换成这样的数组:

myArray= Object.keys(data).map(function(key) { return data[key] });

And sort the result like this:

将结果排序如下:

myArray.sort(function(x, y) {return x.level - y.level});

If you need the id/index, then you need to do a bit more:

如果您需要id/索引,那么您需要做更多:

Object.keys(data).map(function(key) { 
  var obj = data[key];
  obj.index = key;
  return obj 
});

#5


2  

I have stumbled upon that problem recently while trying to group an array of objects by one of it's properties, resulting in one object I could therefore not sort.

我最近偶然发现了这个问题,当时我试图根据一个对象的属性对一个对象数组进行分组,结果导致一个对象无法排序。

Concretely it's an array of blog posts I wanted to group by year and have them sorted by descending years. I used underscore's utility :

具体地说,这是我想按年分类的一系列博客文章,并按年递减排序。我使用了下划线的效用:

var grouped = _.groupBy(blogposts, function(post){
  var date = new Date(post.publication_date)
  return date.getFullYear()
})
//=> { 2010: [blogpost, blogpost,etc], 2011: [blogpost, etc] }

As @Raynos explained I had to end up with some sort of array first before sorting it...

正如@Raynos解释的那样,在排序之前,我必须先处理某种数组……

It turns out underscore (1.4) has a nice little utility called pairs which will map the {key: value} of your object in an array of [key, value]. The equivalent of :

结果显示,下划线(1.4)有一个很好的小实用程序,名为pair,它将在[key, value]数组中映射对象的{key: value}。相当于:

var paired = _.map(grouped, function(val, key){
  return [key, val]
})
//=> [ [2010, [blogpost, blogpost, ...] ], [2011, [blogpost, blogpost, ...]]...]

From there on you can easily sort by the first term of each pair.

从这里开始,你可以很容易地按每对的第一项排序。

Here's the end result:

最终的结果:

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, ...]]...]

I'm sure though there's a better and more performant way, but coming from ruby this code is immediately understandable for me.

我确信,虽然有更好、更高效的方法,但是从ruby中获得的这段代码对我来说是可以理解的。

#6


1  

jQuery offers a map function, which will iterate through each element in an array or object and map the results into a new array.

jQuery提供了一个map函数,它将遍历数组或对象中的每个元素,并将结果映射到一个新的数组中。

Prior to jQuery 1.6, $.map() supported traversing arrays only.

在jQuery 1.6之前,$.map()只支持遍历数组。

We can use this to convert any object to an array as follows...

我们可以使用它将任何对象转换为数组,如下所示……

  myArray = $.map(myObject, function (el) {
    return el;
  });

But... if the callback function returns null or undefined, then that value is removed from the array, in most cases this is useful, but it can cause problems if you need null values in myArray.

但是…如果回调函数返回null或undefined,那么该值将从数组中删除,在大多数情况下这是有用的,但如果在myArray中需要空值,则会导致问题。

jQuery offers a solution for this... return the value as an array with the single value

jQuery为此提供了一个解决方案……将值返回为具有单个值的数组。

myArrayWithNulls = jQuery.map(myObject, function (el) {
  return [el];
});

Here's a fiddle demonstrating the two approaches: http://jsfiddle.net/chim/nFyPE/

这是一个演示这两种方法的小提琴:http://jsfiddle.net/chim/nFyPE/。

http://jsperf.com/object-to-array-jquery-2

http://jsperf.com/object-to-array-jquery-2

#7


1  

I wrote a small function to recursively convert an object with properties that may also be objects to a multi-dimensional array. This code is dependent on underscore or lodash for the forEach and toArray methods.

我编写了一个小函数来递归地将具有属性的对象转换为多维数组。此代码依赖于forEach和toArray方法的下划线或破折号。

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

Here is the fiddle: http://jsfiddle.net/gGT2D/

这是小提琴:http://jsfiddle.net/gGT2D/

Note: This was written to convert an object that was originally an array back into an array, so any non-array index key values will be lost.

注意:这是为了将原来是数组的对象转换回数组,因此将丢失任何非数组索引键值。