Сортировать объект JavaScript по ключу


532

Мне нужно отсортировать объекты JavaScript по ключу.

Отсюда следующее:

{ 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }

Станет:

{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }


39
Еще в 2011 году (когда этот вопрос был опубликован) спецификация ECMAScript гласила, что объекты JavaScript не имеют собственного порядка - наблюдаемый порядок зависит от реализации и, следовательно, на него нельзя положиться. Однако оказывается, что все механизмы JavaScript реализовали более или менее одинаковую семантику, поэтому теперь они стандартизированы в ES6 . В результате многие ответы ниже были правильными согласно спецификации, но теперь неверны.
Матиас Биненс

коротко говоря, используйте отсортированный stringify, когда вам нужно сравнить или хэшировать результаты: npmjs.com/package/json-stable-stringify
exebook

Учитывая, что объекты - это просто карты, или дикты, в зависимости от вашего языка, практически нет причин, по которым вы могли бы сделать это. Сказанное, как правило, порядок, в который они вводятся в карту, фактически является порядком, в котором они находятся при строковом преобразовании. Итак, если вы создали новую карту и присвоили значения на основе предварительно отсортированного списка ключей, вы найдете упорядоченную карту на основе ключей
Fallenreaper

Обратите внимание, что с тех пор Object.entriesи Object.fromEntriesбыли добавлены в JS, это может быть достигнуто с очень коротким однострочником:Object.fromEntries(Object.entries(obj).sort())
Майк 'Pomax' Kamermans

Ответы:


472

Другие ответы на этот вопрос устарели, никогда не соответствовали реальности реализации и официально стали неверными после публикации спецификации ES6 / ES2015.


См. Раздел, посвященный порядку итераций свойств в « Изучении ES6 » Акселя Раушмайера :

Все методы, которые перебирают ключи свойств, делают это в том же порядке:

  1. Сначала все индексы Array, отсортированные по номерам.
  2. Затем все строковые ключи (которые не являются индексами), в том порядке, в котором они были созданы.
  3. Затем все символы в том порядке, в котором они были созданы.

Так что да, объекты JavaScript являются на самом деле упорядочены, и порядок их ключей / свойства могут быть изменены.

Вот как вы можете отсортировать объект по ключам / свойствам в алфавитном порядке:

const unordered = {
  'b': 'foo',
  'c': 'bar',
  'a': 'baz'
};

console.log(JSON.stringify(unordered));
// → '{"b":"foo","c":"bar","a":"baz"}'

const ordered = {};
Object.keys(unordered).sort().forEach(function(key) {
  ordered[key] = unordered[key];
});

console.log(JSON.stringify(ordered));
// → '{"a":"baz","b":"foo","c":"bar"}'

Используйте varвместо constсовместимости с двигателями ES5.


5
Я действительно не вижу разницы в вашем коде и главном ответе здесь, кроме использования немного другой техники зацикливания. Независимо от того, можно ли сказать, что объекты «упорядочены» или нет, не имеет значения. Ответ на этот вопрос остается прежним. Опубликованная спецификация просто подтверждает ответы здесь.
Фил

6
К вашему сведению, было уточнено, что порядок перечисления свойств все еще не определен: esdiscuss.org/topic/…
Феликс Клинг

6
@ Phil_1984_ Этот ответ и самый популярный ответ очень разные. Вопрос OP был в том, как отсортировать литерал объекта. Ответ, получивший наибольшее количество голосов, говорит, что вы не можете, затем предлагает обходной путь, сохраняя отсортированные ключи в массиве, затем итерируя и печатая пары значений ключей из отсортированного массива. В этом ответе утверждается, что порядок литералов объектов теперь можно сортировать, и в его примере значения отсортированного ключа сохраняются обратно в литерал объекта, а затем печатается отсортированный объект напрямую. Кстати, было бы неплохо, если бы этот сайт еще существовал.
cchamberlain

6
Оба ответа просто используют функцию Array.sort, чтобы сначала отсортировать ключи. ОП запрашивает сортировку «объекта JavaScript» и просто использует нотацию объектов JavaScript (JSON) для описания двух объектов. Эти 2 объекта логически идентичны, то есть сортировка не имеет значения. Я думаю, что верхний ответ объясняет это намного лучше. Сказать «все остальные ответы теперь официально неверны» для меня слишком экстремально, особенно с неработающей ссылкой. Я думаю, что проблема в том, что «эта новая спецификация ES6» создает иллюзию, что у объектов Javascript есть упорядоченный список ключей, что просто не соответствует действительности.
Фил

1
Пожалуйста, добавьте, что это решение не поддерживается различными современными браузерами (Google Caniuse ES6). Использование этих ответов может привести к трудностям при обнаружении ошибок только в определенных браузерах (например, Safari, когда с Chrome все в порядке).
Мануэль Арвед Шмидт

244

JavaScript объекты 1 не упорядочены. Бессмысленно пытаться «сортировать» их. Если вы хотите перебрать свойства объекта, вы можете отсортировать ключи и затем извлечь связанные значения:

var myObj = {
    'b': 'asdsadfd',
    'c': 'masdasaf',
    'a': 'dsfdsfsdf'
  },
  keys = [],
  k, i, len;

for (k in myObj) {
  if (myObj.hasOwnProperty(k)) {
    keys.push(k);
  }
}

keys.sort();

len = keys.length;

for (i = 0; i < len; i++) {
  k = keys[i];
  console.log(k + ':' + myObj[k]);
}


Альтернативная реализация с использованием Object.keysфантазии:

var myObj = {
    'b': 'asdsadfd',
    'c': 'masdasaf',
    'a': 'dsfdsfsdf'
  },
  keys = Object.keys(myObj),
  i, len = keys.length;

keys.sort();

for (i = 0; i < len; i++) {
  k = keys[i];
  console.log(k + ':' + myObj[k]);
}


1 Не быть педантичным, но нет такого понятия, как объект JSON .


2
@MarcelKorpel Существует такая вещь, как объект JSON. Проверьте раздел 8 официального JSON RFC: ietf.org/rfc/rfc4627.txt
Пол

8
@Paulpro две вещи, которые следует отметить об этом RFC: во-первых, ему 7 лет, и словарный запас со временем меняется; во-вторых, «В этой заметке содержится информация для интернет-сообщества. В ней не указаны какие-либо стандарты Интернета». Представляет ли данная последовательность символов литерал объекта JavaScript или текст JSON, зависит от контекста / использования. Термин «объект JSON» объединяет и делает различие двусмысленным вредным образом. Давайте избавимся от неточной терминологии и по возможности будем использовать более точный термин. Я не вижу причин поступать иначе. Слова имеют значение.
Мэтт Болл

6
@MattBall IMO JSON Object - очень точный термин для такой строки, {"a", 1}как JSON Array - точный термин для такой строки [1]. Полезно иметь возможность общаться, произнося такие вещи, как третий объект в моем массиве, когда у вас есть строка [{x: 1}, {y: 2}, {z: 3}], поэтому я очень предпочитаю «Это не объект JSON» при комментировании литерала Javascript, а не «Нет такого «вещь как объект JSON», что в дальнейшем вызовет больше путаницы и затруднений в общении, когда OP на самом деле работает с JSON.
Пол

3
@Paulpro Я должен не согласиться. {"a", 1}является либо литералом объекта, либо текстом JSON (или, если хотите, строкой JSON). Что это зависит от контекста, первый, если он появляется дословно в исходном коде JavaScript, второй, если это строка, которую нужно передать в анализатор JSON для дальнейшего использования. Существуют реальные различия между ними, когда речь идет о разрешенном синтаксисе, правильном использовании и сериализации.
Мэтт Болл

4
Теперь, когда ES6 / ES2015 завершена, этот ответ официально стал неправильным. Смотрите мой ответ для получения дополнительной информации.
Матиас Биненс

172

Многие люди упоминают, что «объекты не могут быть отсортированы» , но после этого они дают вам решение, которое работает. Парадокс, не правда ли?

Никто не упоминает, почему эти решения работают. Они есть, потому что в большинстве реализаций браузера значения в объектах хранятся в том порядке, в котором они были добавлены. Поэтому, если вы создаете новый объект из отсортированного списка ключей, он возвращает ожидаемый результат.

И я думаю, что мы могли бы добавить еще одно решение - функциональный путь ES5:

function sortObject(obj) {
    return Object.keys(obj).sort().reduce(function (result, key) {
        result[key] = obj[key];
        return result;
    }, {});
}

ES2015 версия выше (отформатированная в «однострочник»):

const sortObject = o => Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})

Краткое объяснение приведенных выше примеров (как указано в комментариях):

Object.keysдает нам список ключей в предоставленном объекте ( objили o), затем мы сортируем те, используя алгоритм сортировки по умолчанию, затем .reduceиспользуется для преобразования этого массива обратно в объект, но на этот раз со всеми отсортированными ключами.


7
@Pointy Это поведение всегда доступно во всех основных браузерах и было стандартизировано в ES6 / ES2015 . Я бы сказал, что это хороший совет.
Матиас Биненс

3
Это самый простой и краткий способ выполнения задачи в EcmaScript v5. Немного опоздал на вечеринку, но должен быть принят ответ.
Стивен де Салас

2
«Да, потому что в большинстве реализаций браузера значения в объектах хранятся в том порядке, в котором они были добавлены». Только для нечисловых свойств. Также обратите внимание, что до сих пор нет гарантии, в каком порядке будут повторяться свойства (например, через for...in).
Феликс Клинг

2
Приятно, что вы объяснили, почему это работает, это урок для меня. Спасибо!
ол

5
Мой линтер жаловался на эту однострочник (возвращая назначение), но этот работает для меня и мне легче читать:Object.keys(dict).sort().reduce((r, k) => Object.assign(r, { [k]: dict[k] }), {});
Акс.

68

Ребята, я образно шокирован! Конечно, все ответы несколько устарели, но никто даже не упомянул стабильность в сортировке! Так что терпите меня, я сделаю все возможное, чтобы ответить на сам вопрос и вдаваться в подробности здесь. Поэтому я собираюсь извиниться, сейчас будет много читать.

Поскольку это 2018 год, я буду использовать только ES6, все полифилы доступны в документах MDN, которые я приведу в данной части.


Ответ на вопрос:

Если ваши ключи являются только числами, то вы можете безопасно использовать их Object.keys()вместе с Array.prototype.reduce()для возврата отсортированного объекта:

// Only numbers to show it will be sorted.
const testObj = {
  '2000': 'Articel1',
  '4000': 'Articel2',
  '1000': 'Articel3',
  '3000': 'Articel4',
};

// I'll explain what reduces does after the answer.
console.log(Object.keys(testObj).reduce((accumulator, currentValue) => {
  accumulator[currentValue] = testObj[currentValue];
  return accumulator;
}, {}));

/**
 * expected output:
 * {
 * '1000': 'Articel3',
 * '2000': 'Articel1',
 * '3000': 'Articel4',
 * '4000': 'Articel2' 
 *  } 
 */

// if needed here is the one liner:
console.log(Object.keys(testObj).reduce((a, c) => (a[c] = testObj[c], a), {}));

Однако, если вы работаете со строками, я настоятельно рекомендую объединить Array.prototype.sort()все это в цепочку :

// String example
const testObj = {
  'a1d78eg8fdg387fg38': 'Articel1',
  'z12989dh89h31d9h39': 'Articel2',
  'f1203391dhj32189h2': 'Articel3',
  'b10939hd83f9032003': 'Articel4',
};
// Chained sort into all of this.
console.log(Object.keys(testObj).sort().reduce((accumulator, currentValue) => {
  accumulator[currentValue] = testObj[currentValue];
  return accumulator;
}, {}));

/**
 * expected output:   
 * { 
 * a1d78eg8fdg387fg38: 'Articel1',
 * b10939hd83f9032003: 'Articel4',
 * f1203391dhj32189h2: 'Articel3',
 * z12989dh89h31d9h39: 'Articel2' 
 * }
 */

// again the one liner:
console.log(Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}));

Если кому-то интересно, что делает сокращение:

// Will return Keys of object as an array (sorted if only numbers or single strings like a,b,c).
Object.keys(testObj)

// Chaining reduce to the returned array from Object.keys().
// Array.prototype.reduce() takes one callback 
// (and another param look at the last line) and passes 4 arguments to it: 
// accumulator, currentValue, currentIndex and array
.reduce((accumulator, currentValue) => {

  // setting the accumulator (sorted new object) with the actual property from old (unsorted) object.
  accumulator[currentValue] = testObj[currentValue];

  // returning the newly sorted object for the next element in array.
  return accumulator;

  // the empty object {} ist the initial value for  Array.prototype.reduce().
}, {});

Если необходимо, вот объяснение для одного лайнера:

Object.keys(testObj).reduce(

  // Arrow function as callback parameter.
  (a, c) => 

  // parenthesis return! so we can safe the return and write only (..., a);
  (a[c] = testObj[c], a)

  // initial value for reduce.
  ,{}
);

Почему сортировка немного сложна:

Короче Object.keys(), вернет массив с тем же порядком, что и обычный цикл:

const object1 = {
  a: 'somestring',
  b: 42,
  c: false
};

console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]

Object.keys () возвращает массив, элементы которого являются строками, соответствующими перечисляемым свойствам, найденным непосредственно в объекте. Порядок свойств такой же, как и при циклическом переключении свойств объекта вручную.

Sidenote - вы также можете использовать Object.keys()массивы, помните, что индекс будет возвращен:

// simple array
const arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']

Но это не так просто, как показано в этих примерах, объекты реального мира могут содержать цифры и буквы алфавита или даже символы (пожалуйста, не делайте этого).

Вот пример со всеми из них в одном объекте:

// This is just to show what happens, please don't use symbols in keys.
const testObj = {
  '1asc': '4444',
  1000: 'a',
  b: '1231',
  '#01010101010': 'asd',
  2: 'c'
};

console.log(Object.keys(testObj));
// output: [ '2', '1000', '1asc', 'b', '#01010101010' ]

Теперь, если мы используем Array.prototype.sort()вышеупомянутый массив, изменения получатся:

console.log(Object.keys(testObj).sort());
// output: [ '#01010101010', '1000', '1asc', '2', 'b' ]

Вот цитата из документов:

Метод sort () сортирует элементы массива на месте и возвращает массив. Сортировка не обязательно стабильна. Порядок сортировки по умолчанию соответствует строковым кодовым точкам Unicode.

Временная и пространственная сложность сортировки не может быть гарантирована, так как она зависит от реализации.

Вы должны убедиться, что один из них возвращает желаемый результат для вас. В реальных примерах люди склонны смешивать вещи, особенно если вы используете разные информационные входы, такие как API и базы данных вместе.


Так в чем же дело?

Ну, есть две статьи, которые должен понять каждый программист:

Алгоритм на месте :

В компьютерной науке алгоритм на месте - это алгоритм, который преобразует входные данные без использования вспомогательной структуры данных. Однако для вспомогательных переменных допускается небольшое количество дополнительного пространства для хранения. Входные данные обычно перезаписываются выходными данными при выполнении алгоритма. Алгоритм на месте обновляет входную последовательность только путем замены или замены элементов. Алгоритм, который не на месте, иногда называют не на месте или не на месте.

Так что в основном наш старый массив будет перезаписан! Это важно, если вы хотите сохранить старый массив по другим причинам. Так что имейте это в виду.

Алгоритм сортировки

Алгоритмы стабильной сортировки сортируют идентичные элементы в том же порядке, в котором они появляются во входных данных. При сортировке некоторых видов данных при определении порядка сортировки проверяется только часть данных. Например, в примере сортировки карт справа карты сортируются по их рангу, а их масть игнорируется. Это позволяет использовать несколько разных правильно отсортированных версий исходного списка. Стабильные алгоритмы сортировки выбирают один из них в соответствии со следующим правилом: если два элемента сравниваются как равные, как две 5 карты, то их относительный порядок будет сохранен, так что, если одна из них предшествовала другой на входе, она также будет опережать других в выводе.

введите описание изображения здесь

Пример стабильной сортировки по игральным картам. Когда карты отсортированы по рангу со стабильной сортировкой, две 5-ки должны оставаться в том же порядке в отсортированном выводе, в котором они были изначально. Когда они сортируются с нестабильной сортировкой, 5-и могут оказаться в противоположном порядок в отсортированном выводе.

Это показывает, что сортировка верна, но она изменилась. Таким образом, в реальном мире, даже если сортировка правильная, мы должны убедиться, что получаем то, что ожидаем! Это очень важно, имейте это в виду. Дополнительные примеры JavaScript можно найти в Array.prototype.sort () - docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort


3
Вы флиппин рок, спасибо за этот невероятный ответ. Один из лучших, которые я видел на SO. Приветствия.
Гэвин

Если бы вы только могли предложить метод, который вам понадобится в конце. Отличный ответ, хотя!
ммм

@momomo проблема в том, что в зависимости от того, что вы ожидаете от сортировки, нет правильного метода. Однако вы можете просто использовать этот кусок кода из моего ответа: Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}).
Megajin

Разве стабильность вида не применима к этому вопросу: мы сортируем по ключу объекта, а ключ уникален. (Чтобы расширить пример вашей карты: в колоде никогда не может быть двух пятерок, даже если они разных мастей.)
Даррен Кук

@DarrenCook хороший вопрос! Вы правы, никогда не будет одинакового ключа в одном объекте. Однако стабильность сложнее, чем просто уникальность ключа. Большую часть времени массив включается в сортировку объектов. И тогда все может стать нестабильным. Представьте себе карточную игру с 5 игроками. Каждая рука представлена ​​массивом (для сортировки отдельных рук) и карточками как объектами. Если ваша карта выглядит так {5: 'hearts'}или {5: 'spades'}вы начинаете сортировать массив, она станет потенциально нестабильной в таких играх, как рамми. Не говорить на разных языках.
Мегаджин

29

Это работает для меня

/**
 * Return an Object sorted by it's Key
 */
var sortObjectByKey = function(obj){
    var keys = [];
    var sorted_obj = {};

    for(var key in obj){
        if(obj.hasOwnProperty(key)){
            keys.push(key);
        }
    }

    // sort keys
    keys.sort();

    // create new array based on Sorted Keys
    jQuery.each(keys, function(i, key){
        sorted_obj[key] = obj[key];
    });

    return sorted_obj;
};

10
Это на самом деле правильный ответ на поставленный вопрос. Для упрощенной версии с помощью подчеркивания, см: jsfiddle.net/wPjaQ/1
подкоренное

6
@radicand Нет, этот ответ не правильный. Возвращает новый объект, который также не имеет порядка.
Пол

3
@radicand Это не на практике либо. Нет такой вещи как порядок на ключах объектов, так как вы можете сказать, что на практике это дает вам объект в отсортированном порядке? Это действительно просто возвращает вам мелкую копию объекта, который вы передаете.
Пол

9
Это супер неправильно. Это может произойти на данный момент, но будет зависать в другом веб-браузере или другой загрузки страницы в том же браузере. Браузеры могут рандомизировать ключи объекта в целях безопасности, или когда вы заполняете объект, он помещает значения в разные области памяти в зависимости от ключей, что будет возвращать другой порядок. Если это сработало, вам просто повезло.
Йоберт

11
Это также имеет ненужное использование jQuery.
RobG

25

Это 2019 год, и у нас есть 2019 способ решить эту проблему :)

Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())

2
Как мы сортируем вложенные объекты по ключу?
a2441918

@ a2441918 Точно так же, как вы делали бы с функцией sort (). Посмотрите: developer.mozilla.org/de/docs/Web/JavaScript/Reference/… Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). Sort ((k, j ) => k - j))
user2912903

Для пользователей TypeScript это еще не доступно для нас, см .: github.com/microsoft/TypeScript/issues/30933
tsujp

Хорошая строчка, но как сортировать ключи без учета регистра?
TheMaxx

1
@theMaxx Используйте пользовательскую функцию для сортировки, например: `` `Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). sort (([key1, val1], [key2, val2]) => key1.toLowerCase (). localeCompare (key2.toLowerCase ()))) `` `
Бен

22

вот 1 лайнер

var data = { zIndex:99,
             name:'sravan',
             age:25, 
             position:'architect',
             amount:'100k',
             manager:'mammu' };

console.log(Object.entries(data).sort().reduce( (o,[k,v]) => (o[k]=v,o), {} ));


Какого черта этот сумасшедший синтаксис? (o[k] = v, o), Почему это даже работает, где я могу найти документы об этом? Очевидно, он возвращает самый правый параметр, но почему?
Ntaso


короткая функция сначала o[k]равняется, vа затем возвращаетсяo
Tahsin Turkoz

19

Это старый вопрос, но, следуя ответу Матиаса Биненса, я сделал короткую версию для сортировки текущего объекта без особых накладных расходов.

    Object.keys(unordered).sort().forEach(function(key) {
        var value = unordered[key];
        delete unordered[key];
        unordered[key] = value;
    });

после выполнения кода для самого «неупорядоченного» объекта ключи будут отсортированы в алфавитном порядке.


17

Используя lodash это будет работать:

some_map = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }

// perform a function in order of ascending key
_(some_map).keys().sort().each(function (key) {
  var value = some_map[key];
  // do something
});

// or alternatively to build a sorted list
sorted_list = _(some_map).keys().sort().map(function (key) {
  var value = some_map[key];
  // return something that shall become an item in the sorted list
}).value();

Просто пища для размышлений.


15

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

(function(s){var t={};Object.keys(s).sort().forEach(function(k){t[k]=s[k]});return t})({b:2,a:1,c:3})

Огромное спасибо loooot
Мугивара

Ницца! Спасибо за это краткое решение.
Кон Антонакос

9

Подчеркнуть версию :

function order(unordered)
{
return _.object(_.sortBy(_.pairs(unordered),function(o){return o[0]}));
}

Если вы не доверяете своему браузеру в сохранении порядка ключей, я настоятельно рекомендую полагаться на упорядоченный массив парных массивов ключ-значение.

_.sortBy(_.pairs(c),function(o){return o[0]})

Лучше:_.object(_.sortBy(_.pairs(unordered), _.first))
Афанасий Куракин

8
function sortObjectKeys(obj){
    return Object.keys(obj).sort().reduce((acc,key)=>{
        acc[key]=obj[key];
        return acc;
    },{});
}

sortObjectKeys({
    telephone: '069911234124',
    name: 'Lola',
    access: true,
});

Может быть, лучше добавить какое-нибудь объяснение вашего кода.
Аристотель

1
Получает ключи объекта, поэтому это массив строк, я их сортирую () и, так как это массив строк (ключей), я уменьшаю их (с помощью Reduce () из js Array). Первоначально acc является пустым объектом {} (последний аргумент редуктора), а редуктор (обратный вызов) присваивает пустому объекту значения исходного объекта с упорядоченной последовательностью ключей.
user3286817

8

Может быть, немного более элегантная форма:

 /**
     * Sorts a key-value object by key, maintaining key to data correlations.
     * @param {Object} src  key-value object
     * @returns {Object}
     */
var ksort = function ( src ) {
      var keys = Object.keys( src ),
          target = {};
      keys.sort();
      keys.forEach(function ( key ) {
        target[ key ] = src[ key ];
      });
      return target;
    };


// Usage
console.log(ksort({
  a:1,
  c:3,
  b:2  
}));

PS и то же самое с синтаксисом ES6 +:

function ksort( src ) {
  const keys = Object.keys( src );
  keys.sort();
  return keys.reduce(( target, key ) => {
        target[ key ] = src[ key ];
        return target;
  }, {});
};

это ничего не сортирует. Вы все еще возвращаете объект. Вы не можете гарантировать, что объекты в вашей цели фактически будут иметь какой-либо порядок. вам нужно вернуть массив. jeeezus.
ммм

единственное, что вы здесь делаете, - это неоптимальный набор.
ммм

7

рекурсивная сортировка для вложенных объектов и массивов

function sortObjectKeys(obj){
    return Object.keys(obj).sort().reduce((acc,key)=>{
        if (Array.isArray(obj[key])){
            acc[key]=obj[key].map(sortObjectKeys);
        }
        if (typeof obj[key] === 'object'){
            acc[key]=sortObjectKeys(obj[key]);
        }
        else{
            acc[key]=obj[key];
        }
        return acc;
    },{});
}

// test it
sortObjectKeys({
    telephone: '069911234124',
    name: 'Lola',
    access: true,
    cars: [
        {name: 'Family', brand: 'Volvo', cc:1600},
        {
            name: 'City', brand: 'VW', cc:1200, 
            interior: {
                wheel: 'plastic',
                radio: 'blaupunkt'
            }
        },
        {
            cc:2600, name: 'Killer', brand: 'Plymouth',
            interior: {
                wheel: 'wooden',
                radio: 'earache!'
            }
        },
    ]
});

Я думаю, что вам нужно elseтам - может быть верно как для, так Array.isArray(obj[key])и дляtypeof obj[key] === 'object'
jononomo

Когда у вас есть массив примитивов, ваша функция преобразует примитивы (строка / число) в пустые объекты. Чтобы поймать это, я добавил следующее в начале вашей функции function sortObjectKeys(obj){:: if(typeof obj != 'object'){ /* it is a primitive: number/string (in an array) */ return obj; }. Для устойчивости я при полном запуске также добавил:if(obj == null || obj == undefined){ return obj; }
isgoed

4

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

Однако...

Вы можете найти эту идиому полезной:

var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };

var kv = [];

for (var k in o) {
  kv.push([k, o[k]]);
}

kv.sort()

Затем вы можете перебирать kv и делать все, что пожелаете.

> kv.sort()
[ [ 'a', 'dsfdsfsdf' ],
  [ 'b', 'asdsad' ],
  [ 'c', 'masdas' ] ]


4

Вот чистая версия на основе lodash, которая работает с вложенными объектами

/**
 * Sort of the keys of an object alphabetically
 */
const sortKeys = function(obj) {
  if(_.isArray(obj)) {
    return obj.map(sortKeys);
  }
  if(_.isObject(obj)) {
    return _.fromPairs(_.keys(obj).sort().map(key => [key, sortKeys(obj[key])]));
  }
  return obj;
};

Было бы еще чище, если бы у Лодаша был toObject()метод ...


3

Просто используйте lodash, чтобы разархивировать map и sortBy первое значение пары, и снова заархивировать, чтобы вернуть отсортированный ключ.

Если вы хотите отсортировать значение, измените индекс пары на 1 вместо 0

var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };
console.log(_(o).toPairs().sortBy(0).fromPairs().value())

введите описание изображения здесь


Пожалуйста, используйте ссылку редактирования, чтобы объяснить, как работает этот код, а не просто давать код, так как объяснение с большей вероятностью поможет будущим читателям. Смотрите также Как ответить . Источник
Джед Фокс,

3

Сортирует ключи рекурсивно, сохраняя ссылки.

function sortKeys(o){
    if(o && o.constructor === Array)
        o.forEach(i=>sortKeys(i));
    else if(o && o.constructor === Object)
        Object.entries(o).sort((a,b)=>a[0]>b[0]?1:-1).forEach(e=>{
            sortKeys(e[1]);
            delete o[e[0]];
            o[e[0]] = e[1];
        });
}

Пример:

let x = {d:3, c:{g:20, a:[3,2,{s:200, a:100}]}, a:1};
let y = x.c;
let z = x.c.a[2];
sortKeys(x);
console.log(x); // {a: 1, c: {a: [3, 2, {a: 1, s: 2}], g: 2}, d: 3}
console.log(y); // {a: [3, 2, {a: 100, s: 200}}, g: 20}
console.log(z); // {a: 100, s: 200}

Хороший фрагмент! Какова цель delete o[e[0]];там? Мы не можем просто назначить?
Боянг

Кажется, что только новые назначения несуществующим ключам добавят ключ в конце. Если удаление закомментировано, ключи не будут отсортированы, по крайней мере, в Chrome.
Brunettdan

в этом есть смысл. Спасибо! В любом случае, это своего рода безнадежная причина, потому что ключи объекта js не имеют последовательности, согласно спецификациям. Мы просто эксплуатируют OBJ и журнала функции детали осущ
Boyang

Да, я использую карту, когда важен порядок ключей: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
brunettdan


3

Это облегченное решение для всего, что мне нужно для сортировки JSON.

function sortObj(obj) {
    if (typeof obj !== "object" || obj === null)
        return obj;

    if (Array.isArray(obj))
        return obj.map((e) => sortObj(e)).sort();

    return Object.keys(obj).sort().reduce((sorted, k) => {
        sorted[k] = sortObj(obj[k]);
        return sorted;
    }, {});
}

2

Используйте этот код, если у вас есть вложенные объекты или если у вас есть вложенный массив obj.

var sortObjectByKey = function(obj){
    var keys = [];
    var sorted_obj = {};
    for(var key in obj){
        if(obj.hasOwnProperty(key)){
            keys.push(key);
        }
    }
    // sort keys
    keys.sort();

    // create new array based on Sorted Keys
    jQuery.each(keys, function(i, key){
        var val = obj[key];
        if(val instanceof Array){
            //do for loop;
            var arr = [];
            jQuery.each(val,function(){
                arr.push(sortObjectByKey(this));
            }); 
            val = arr;

        }else if(val instanceof Object){
            val = sortObjectByKey(val)
        }
        sorted_obj[key] = val;
    });
    return sorted_obj;
};

5
Автор не утверждает, что он использует jQuery, и вопрос не помечен как jQuery. Было бы неплохо, если бы вы добавили решение в чистом javascript.
rusmus

Спасибо @Phani, это именно то, что мне нужно
Уилл Шеппард

2

Решение:

function getSortedObject(object) {
  var sortedObject = {};

  var keys = Object.keys(object);
  keys.sort();

  for (var i = 0, size = keys.length; i < size; i++) {
    key = keys[i];
    value = object[key];
    sortedObject[key] = value;
  }

  return sortedObject;
}

// Test run
getSortedObject({d: 4, a: 1, b: 2, c: 3});

Объяснение:

Многие среды выполнения JavaScript хранят значения внутри объекта в порядке их добавления.

Чтобы отсортировать свойства объекта по его ключам, вы можете использовать функцию Object.keys, которая будет возвращать массив ключей. Массив ключей затем можно отсортировать с помощью метода Array.prototype.sort (), который сортирует элементы массива на месте (нет необходимости присваивать их новой переменной).

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

Ниже приведен пример процедуры (вы можете проверить ее в целевых браузерах):

/**
 * Returns a copy of an object, which is ordered by the keys of the original object.
 *
 * @param {Object} object - The original object.
 * @returns {Object} Copy of the original object sorted by keys.
 */
function getSortedObject(object) {
  // New object which will be returned with sorted keys
  var sortedObject = {};

  // Get array of keys from the old/current object
  var keys = Object.keys(object);
  // Sort keys (in place)
  keys.sort();

  // Use sorted keys to copy values from old object to the new one
  for (var i = 0, size = keys.length; i < size; i++) {
    key = keys[i];
    value = object[key];
    sortedObject[key] = value;
  }

  // Return the new object
  return sortedObject;
}

/**
 * Test run
 */
var unsortedObject = {
  d: 4,
  a: 1,
  b: 2,
  c: 3
};

var sortedObject = getSortedObject(unsortedObject);

for (var key in sortedObject) {
  var text = "Key: " + key + ", Value: " + sortedObject[key];
  var paragraph = document.createElement('p');
  paragraph.textContent = text;
  document.body.appendChild(paragraph);
}

Примечание. Object.keys - это метод ECMAScript 5.1, но для старых браузеров используется полифил:

if (!Object.keys) {
  Object.keys = function (object) {
    var key = [];
    var property = undefined;
    for (property in object) {
      if (Object.prototype.hasOwnProperty.call(object, property)) {
        key.push(property);
      }
    }
    return key;
  };
}

2

Я передал некоторые перечисления Java в объекты JavaScript.

Эти объекты вернули мне правильные массивы. если ключи объекта имеют смешанный тип (string, int, char), возникает проблема.

Types:

var TypeA = {
    "-1": "Any",
    "2": "2L",
    "100": "100L",
    "200": "200L",
    "1000": "1000L"
};

var TypeB = {
    "U": "Any",
    "W": "1L",
    "V": "2L",
    "A": "100L",
    "Z": "200L",
    "K": "1000L"
};


Sorted Keys(output):

Key list of TypeA -> ["-1", "2", "100", "200", "1000"]

Key list of TypeB -> ["U", "W", "V", "A", "Z", "K"]

2

Простой и читаемый фрагмент кода с использованием lodash.

Ключ нужно заключать в кавычки только при вызове sortBy. Это не должно быть в кавычках в самих данных.

_.sortBy(myObj, "key")

Кроме того, ваш второй параметр для отображения неверен. Это должна быть функция, но проще использовать pluck.

_.map( _.sortBy(myObj, "key") , "value");

2

Есть замечательный проект @sindresorhus, называемый sort-keys, который работает потрясающе.

Вы можете проверить его исходный код здесь:

https://github.com/sindresorhus/sort-keys

Или вы можете использовать его с npm:

$ npm install --save sort-keys

Вот также примеры кода из его readme

const sortKeys = require('sort-keys');

sortKeys({c: 0, a: 0, b: 0});
//=> {a: 0, b: 0, c: 0}

sortKeys({b: {b: 0, a: 0}, a: 0}, {deep: true});
//=> {a: 0, b: {a: 0, b: 0}}

sortKeys({c: 0, a: 0, b: 0}, {
    compare: (a, b) => -a.localeCompare(b)
});
//=> {c: 0, b: 0, a: 0}

1

Чистый ответ JavaScript для сортировки объекта. Это единственный ответ, который я знаю, который будет обрабатывать отрицательные числа. Эта функция предназначена для сортировки числовых объектов.

Введите obj = {1000: {}, -1200: {}, 10000: {}, 200: {}};

function osort(obj) {
var keys = Object.keys(obj);
var len = keys.length;
var rObj = [];
var rK = [];
var t = Object.keys(obj).length;
while(t > rK.length) {
    var l = null;
    for(var x in keys) {
        if(l && parseInt(keys[x]) < parseInt(l)) {
            l = keys[x];
            k = x;
        }
        if(!l) { // Find Lowest
            var l = keys[x];
            var k = x;
        }
    }
    delete keys[k];
    rK.push(l);
}

for (var i = 0; i < len; i++) {

    k = rK[i];
    rObj.push(obj[k]);
}
return rObj;
}

Выходными данными будет объект, отсортированный по этим числам с новыми ключами, начинающимися с 0.


1

Просто чтобы упростить это и сделать его более ясным ответ от Мэтта Болла

//your object
var myObj = {
    b : 'asdsadfd',
    c : 'masdasaf',
    a : 'dsfdsfsdf'
  };

//fixed code
var keys = [];
for (var k in myObj) {
  if (myObj.hasOwnProperty(k)) {
    keys.push(k);
  }
}
keys.sort();
for (var i = 0; i < keys.length; i++) {
  k = keys[i];
  alert(k + ':' + myObj[k]);
}


1

Не уверен, что это отвечает на вопрос, но это то, что мне было нужно.

Maps.iterate.sorted = function (o, callback) {
    var keys = Object.keys(o), sorted = keys.sort(), k; 
    if ( callback ) {
            var i = -1;
            while( ++i < sorted.length ) {
                    callback(k = sorted[i], o[k] );
            }
    }

    return sorted;
}

Называется как:

Maps.iterate.sorted({c:1, b:2, a:100}, function(k, v) { ... } ) 

1

Одна строка:

Object.entries(unordered)
  .sort(([keyA], [keyB]) => keyA > keyB)
  .reduce((obj, [key,value]) => Object.assign(obj, {[key]: value}), {})

1

лучший способ сделать это

 const object =  Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})

 //else if its in reverse just do 

 const object = Object.keys(0).reverse ()

Вы можете сначала преобразовать ваш почти подобный массиву объект в реальный массив, а затем использовать .reverse ():

Object.assign([], {1:'banana', 2:'apple', 
3:'orange'}).reverse();
// [ "orange", "apple", "banana", <1 empty slot> ]

Пустой слот в конце, если причина, потому что ваш первый индекс равен 1 вместо 0. Вы можете удалить пустой слот с помощью .length- или .pop ().

В качестве альтернативы, если вы хотите заимствовать .reverse и вызвать его для того же объекта, это должен быть объект, похожий на массив. То есть ему нужно свойство длины:

Array.prototype.reverse.call({1:'banana', 2:'apple', 
3:'orange', length:4});
// {0:"orange", 1:"apple", 3:"banana", length:4}

Обратите внимание, что он вернет тот же объект, полностью похожий на массив, поэтому он не будет настоящим массивом. Затем вы можете использовать delete для удаления свойства длины.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.