Как отсортировать объект Javascript или преобразовать его в массив? - PullRequest
37 голосов
/ 08 февраля 2011

У меня есть некоторые данные JSON, которые я получаю с сервера.В моем JavaScript я хочу сделать сортировку по нему.Я думаю, что функция sort () будет делать то, что я хочу.

Однако, похоже, что JavaScript преобразует данные JSON в объект сразу по прибытии.Если я пытаюсь использовать метод sort (), я получаю множество ошибок (использую Firebug для тестирования).

Я осмотрел сеть, и все, кажется, говорят, что, с одной стороны, объекты JSONуже являются массивами JavaScript, а также то, что объекты могут рассматриваться как массивы.Как и на этом вопросе , где в одном из ответов парень говорит: «[Объектный объект] - это ваши данные - вы можете обращаться к ним, как к массиву».

Однако это не совсем так.JavaScript не позволит мне использовать sort () для моего объекта.И поскольку по умолчанию предполагается, что они все одно и то же, похоже, нигде нет никаких инструкций о том, как преобразовать объект в массив, или заставить JavaScript обрабатывать его как единое целое или что-то в этом роде.

Итак ... как мне получить JavaScript, который позволил бы мне обрабатывать эти данные как массив и сортировать () их?

Вывод журнала в консоль для моего объекта выглядит следующим образом (я хочу иметь возможностьсортировать по значениям в "уровне"):

OBJECT 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 ]

42 голосов
/ 08 февраля 2011

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

См. живой пример

7 голосов
/ 08 февраля 2011

Вы должны быть в состоянии преобразовать объект 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 .

6 голосов
/ 13 ноября 2011

Если ваш объект JavaScript является массивоподобным объектом , то есть экземпляром Object с допустимым числовым свойством length, то вы можете напрямую использовать множество native методов Array на это благодаря 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 включительно, как в массиве. Другие свойства объекта не будут переупорядочены.

5 голосов
/ 19 февраля 2016

Большинство из этих ответов слишком усложняют проблему или используют JQuery или Underscore, тогда как OP никогда их не запрашивал.

Вы можете преобразовать объект в массив, подобный этому:

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

И отсортируйте результат следующим образом:

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

Если вам нужен идентификатор / индекс, вам нужно сделать немного больше:

Object.keys(data).map(function(key) { 
  var obj = data[key];
  obj.index = key;
  return obj 
});
2 голосов
/ 21 марта 2013

Недавно я наткнулся на эту проблему, пытаясь сгруппировать массив объектов по одному из его свойств, в результате чего я не смог отсортировать один объект.

Конкретно это массив постов в блоге, которые я хотел сгруппировать по годам и отсортировать по убыванию.Я использовал утилиту подчеркивания:

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} вашего объекта в массив [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, этот код мне сразу понятен.

1 голос
/ 16 января 2014

Я написал небольшую функцию для рекурсивного преобразования объекта со свойствами, которые также могут быть объектами, в многомерный массив.Этот код зависит от подчеркивания или 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/

Примечание: это было написано для преобразования объекта, который былмассив обратно в массив, поэтому любые значения ключа индекса не из массива будут потеряны.

1 голос
/ 07 октября 2013

jQuery предлагает функцию map, которая будет перебирать каждый элемент массива или объекта и отображать результаты в новый массив.

До jQuery 1.6, $ .map () поддерживал только массивы обхода.

Мы можем использовать это для преобразования любого объекта в массив следующим образом ...

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

Но ... если функция обратного вызова возвращает null или undefined , то это значение удалено из массива, в большинстве случаев это полезно, но может вызвать проблемы, если вам нужны нулевые значения в myArray.

jQuery предлагает решение для этого ... вернуть значение в виде массива с единственным значением

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

Вот скрипка, демонстрирующая два подхода: http://jsfiddle.net/chim/nFyPE/

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...