it-swarm.com.ru

Как отсортировать объект Javascript или преобразовать его в массив?

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

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

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

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

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

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

OBJECT JSONdata

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

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

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

42
Raynos

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

7
alex

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

6
Luc125

Большинство из этих ответов слишком усложняют проблему или используют 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 
});
5
andyhasit

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

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

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

Как объяснил @Raynos, я должен был получить какой-то массив перед тем, как его отсортировать ... 

Оказывается, в underscore (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 этот код сразу понятен для меня.

2
charlysisto

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

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

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

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

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

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

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

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

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

1
chim

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