Как отсортировать объект Javascript или преобразовать его в массив?
У меня есть данные JSON, которые я получаю с сервера. В моем JavaScript я хочу сделать некоторую сортировку. Я думаю, что функция sort() будет делать то, что я хочу.
Однако, похоже, что JavaScript преобразует данные JSON в объект сразу по прибытии. Если я попытаюсь использовать метод sort(), я получаю ошибки a-много (используя Firebug для тестирования).
Я просмотрел сеть, и все, кажется, говорят, что, с одной стороны, объекты JSON уже являются массивами JavaScript, а также что объекты можно обрабатывать так же, как массивы. Как и на этот вопрос, где в одном из ответов парень говорит: "Объект объекта - это ваши данные - вы можете получить к нему доступ, как и массив."
Однако это не совсем так. JavaScript не позволит мне использовать sort() для моего объекта. И поскольку предположение по умолчанию состоит в том, что все они одно и то же, нет никаких инструкций о том, как преобразовать объект в массив, или заставить JavaScript обрабатывать его как один или что-то в этом роде.
Итак... как мне получить JavaScript, чтобы позволить мне рассматривать эти данные как массив и сортировать() это?
Выход журнала консоли моего объекта выглядит следующим образом (я хочу, чтобы сортировать по значениям на уровне ")":
ОБЪЕКТ JSONdatap >
{
1: {
displayName: "Dude1",
email: "[email protected]<mailto:[email protected]>",
lastActive: 1296980700,
level: 57,
timeout: 12969932837
}, 2: {
displayName: "Dude2",
email: "[email protected]<mailto:[email protected]>",
lastActive: 1296983456,
level: 28,
timeout: 12969937382
}, 3: {
displayName: "Dude3",
email: "[email protected]<mailto:[email protected]>",
lastActive: 1296980749,
level: 99,
timeout: 129699323459
}
}
Ответы
Ответ 1
Array.prototype.slice.call(arrayLikeObject)
- стандартный способ преобразования и массивный объект в массив.
Это действительно работает только для объекта 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"]
. Они не являются реальными ассоциативными массивами, поскольку объекты являются неупорядоченными списками.
Объекты и массивы сильно различаются.
Пример использования подчеркивания:
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;
});
Смотрите живой пример
Ответ 2
Вы должны иметь возможность конвертировать объект 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.
Ответ 3
Если ваш объект JavaScript является подобным массиву объекту, то есть экземпляр объекта с допустимым численным свойством length
, то вы можете напрямую использовать на нем много методов массива, благодаря call
. Например:
// Sorts the given objet in-place as if it was an array
Array.prototype.sort.call(yourObject);
Итак, если вы знаете количество записей для сортировки (Как эффективно подсчитывать количество ключей/свойств объекта в JavaScript?), вы можете сделать
yourObject.length = theNumberOfEntries;
Array.prototype.sort.call(yourObject);
// Optionally: delete yourObject.length;
Обратите внимание, что это будет только сортировка свойств, индексированных значениями "0", "1", "2",... до length - 1
включительно, как в массиве. Объект других свойств не будет переназначен.
Ответ 4
Большинство из этих ответов слишком усложняют проблему или используют JQuery или Underscore, тогда как OP никогда не запрашивал их.
Вы можете преобразовать объект в массив следующим образом:
myArray= Object.keys(data).map(function(key) { return data[key] });
И отсортируйте результат следующим образом:
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
});
Ответ 5
Я недавно наткнулся на эту проблему, пытаясь сгруппировать массив объектов одним из его свойств, в результате чего один объект я не мог сортировать.
Конкретно это массив сообщений в блогах, которые я хотел объединить в год, и отсортировать их по годам. Я использовал утилиту underscore:
var grouped = _.groupBy(blogposts, function(post){
var date = new Date(post.publication_date)
return date.getFullYear()
})
//=> { 2010: [blogpost, blogpost,etc], 2011: [blogpost, etc] }
Как пояснил @Raynos, мне пришлось сначала обработать какой-то массив, прежде чем сортировать его...
Получается, что подчеркивание (1.4) имеет небольшую полезную утилиту под названием pairs
, которая отобразит значение {key: value} вашего объекта в массиве [ключ, значение]. Эквивалент:
var paired = _.map(grouped, function(val, key){
return [key, val]
})
//=> [ [2010, [blogpost, blogpost, ...] ], [2011, [blogpost, blogpost, ...]]...]
Оттуда вы можете легко отсортировать первый член каждой пары.
Здесь конечный результат:
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, этот код мне сразу понятен.
Ответ 6
jQuery предлагает функцию отображения, которая будет перебирать каждый элемент в массиве или объекте и отображать результаты в новый массив.
До того, как только jQuery 1.6 поддерживает только массивы перемещения только $.map().
Мы можем использовать это для преобразования любого объекта в массив следующим образом:
myArray = $.map(myObject, function (el) {
return el;
});
Но...
если функция обратного вызова возвращает null или undefined, то это значение удалено из массива, в большинстве случаев это полезно, но это может вызвать проблемы, если вам нужно null значения в myArray.
jQuery предлагает решение для этого...
вернуть значение в виде массива с единственным значением
myArrayWithNulls = jQuery.map(myObject, function (el) {
return [el];
});
Вот сценарий, демонстрирующий два подхода:
http://jsfiddle.net/chim/nFyPE/
http://jsperf.com/object-to-array-jquery-2
Ответ 7
Я написал небольшую функцию для рекурсивного преобразования объекта со свойствами, которые также могут быть объектами для многомерного массива. Этот код зависит от подчеркивания или lodash для методов 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;
}
Вот скрипка:
http://jsfiddle.net/gGT2D/
Примечание. Это было записано для преобразования объекта, который изначально был массивом обратно в массив, поэтому любые значения ключа индекса без массива будут потеряны.