Classificar objeto JavaScript por chave

532

Preciso classificar objetos JavaScript por chave.

Daí o seguinte:

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

Se tornaria:

{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }
vdh_ant
fonte
3
possível duplicata de Classificando um objeto JSON em Javascript
abraham
39
Em 2011 (quando esta pergunta foi publicada), a especificação do ECMAScript dizia que os objetos JavaScript não têm uma ordem inerente - a ordem observada era dependente da implementação e, portanto, não podia ser invocada. No entanto, todos os mecanismos JavaScript implementaram mais ou menos a mesma semântica, portanto esses já foram padronizados no ES6 . Como resultado, muitas das respostas abaixo costumavam estar corretas conforme as especificações, mas agora estão incorretas.
Mathias Bynens
dizendo brevemente usar ordenado stringify quando você precisar comparar ou hash os resultados: npmjs.com/package/json-stable-stringify
exebook
Dado que os objetos são apenas mapas, ou dictos, dependendo do seu idioma, há pouca ou nenhuma razão para você fazer isso. QUE ESTÁ DIZIDO, geralmente, a ordem em que eles são injetados em um mapa é, de fato, a ordem em que eles residem durante a stringificação. Então, se você criou um novo mapa e valores atribuídos com base em uma lista de chaves pré-classificados, você vai encontrar-se um mapa ordenado com base em chaves
Fallenreaper
Observe que, desde então, Object.entriese Object.fromEntriesforam adicionados ao JS, isso pode ser alcançado com uma única linha bem curta:Object.fromEntries(Object.entries(obj).sort())
Mike 'Pomax' Kamermans

Respostas:

471

As outras respostas a esta pergunta estão desatualizadas, nunca correspondem à realidade da implementação e ficaram oficialmente incorretas agora que as especificações do ES6 / ES2015 foram publicadas.


Consulte a seção sobre ordem de iteração de propriedade em Explorando o ES6 por Axel Rauschmayer :

Todos os métodos que iteram sobre as chaves de propriedade fazem isso na mesma ordem:

  1. Primeiro todos os índices de matriz, classificados numericamente.
  2. Em seguida, todas as chaves de sequência (que não são índices), na ordem em que foram criadas.
  3. Em seguida, todos os símbolos, na ordem em que foram criados.

Portanto, sim, os objetos JavaScript são de fato ordenados e a ordem de suas chaves / propriedades pode ser alterada.

Veja como você pode classificar um objeto por suas chaves / propriedades em ordem alfabética:

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"}'

Use em varvez de constpara compatibilidade com os mecanismos ES5.

Mathias Bynens
fonte
5
Eu realmente não consigo ver uma diferença no seu código e a resposta principal aqui, além de usar uma técnica de loop ligeiramente diferente. Se os objetos podem ou não ser "ordenados" ou não, parece ser irrelevante. A resposta a esta pergunta ainda é a mesma. A especificação publicada apenas confirma as respostas aqui.
Phil
6
FYI, foi esclarecido que a enumeração ordem das propriedades ainda é indefinido: esdiscuss.org/topic/...
Felix Kling
6
@ Phil_1984_ Esta resposta e a resposta mais votada são muito diferentes. A pergunta do OP era como classificar um objeto literal. A resposta mais votada diz que você não pode e, em seguida, fornece uma solução alternativa armazenando chaves classificadas em uma matriz, repetindo e imprimindo pares de valores de chave a partir da matriz classificada. Esta resposta afirma que a ordem dos literais do objeto agora pode ser classificada e seu exemplo armazena os valores da chave classificada de volta em um literal do objeto e depois imprime o objeto classificado diretamente. Em uma nota lateral, seria bom se o site vinculado ainda existisse.
Cchamberlain 14/03
6
Ambas as respostas simplesmente usam a função Array.sort para classificar as chaves primeiro. O OP está pedindo para classificar um "objeto JavaScript" e está apenas usando o JavaScript Object Notation (JSON) para descrever os 2 objetos. Esses 2 objetos são logicamente idênticos, e a classificação é irrelevante. Eu acho que a resposta principal explica isso muito melhor. Dizer "todas as outras respostas agora estão oficialmente incorretas" é muito extremo para mim, especialmente com um link quebrado. Eu acho que o problema é "essa nova especificação do ES6" está dando a ilusão de que os objetos Javascript têm uma lista ordenada de chaves que simplesmente não é verdadeira.
Phil
1
Por favor, adicione que esta solução não é suportada por uma variedade de navegadores modernos (google "caniuse ES6"). O uso dessas respostas corre o risco de encontrar erros difíceis de encontrar apenas em alguns navegadores (por exemplo, Safari quando o Chrome está bom).
Manuel Arwed Schmidt
244

Os objetos JavaScript 1 não estão ordenados. Não faz sentido tentar "classificá-las". Se você deseja iterar sobre as propriedades de um objeto, pode classificar as chaves e recuperar os valores associados:

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


Implementação alternativa usando Object.keysfantasia:

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 Não é pedante, mas não existe um objeto JSON .

Matt Ball
fonte
2
@MarcelKorpel Existe um objeto JSON. Verifique a seção 8 do JSON RFC oficial: ietf.org/rfc/rfc4627.txt
Paul
8
@ Paululpro duas coisas a serem observadas sobre essa RFC: primeiro, ela tem 7 anos e o vocabulário muda com o tempo; segundo, "Este memorando fornece informações para a comunidade da Internet. Não especifica nenhum tipo de padrão da Internet". Se uma determinada sequência de caracteres representa um literal de objeto JavaScript ou um texto JSON depende do contexto / uso. O termo "objeto JSON" conflita e torna a distinção ambígua de maneira prejudicial. Vamos nos livrar da terminologia imprecisa e usar o termo mais preciso sempre que possível. Não vejo razão para fazer o contrário. Palavras importam.
Matt Bola
6
@MattBall IMO JSON Object é um termo muito preciso para uma string, assim {"a", 1}como JSON Array é um termo preciso para uma string como [1]. É útil poder se comunicar dizendo coisas como o terceiro objeto na minha matriz quando você tem a string [{x: 1}, {y: 2}, {z: 3}], então eu prefiro "Isso não é um objeto JSON" ao comentar sobre um literal Javascript, em vez de "Não existe tal como um objeto JSON ", que só causará mais confusão e dificuldades de comunicação mais tarde, quando o OP realmente estiver trabalhando com JSON.
Paul
3
@ Paulpro Eu devo discordar. {"a", 1}é um literal de objeto ou um texto JSON (também conhecido como string JSON, se você realmente preferir). Depende do contexto; o primeiro, se aparecer literalmente no código-fonte JavaScript; o segundo, se for uma sequência que precisa ser passada para um analisador JSON para ser usada posteriormente. Existem diferenças reais entre os dois quando se trata de sintaxe permitida, uso correto e serialização.
Matt Bola
4
Agora que o ES6 / ES2015 foi finalizado, esta resposta ficou oficialmente incorreta. Veja minha resposta para mais informações.
Mathias Bynens
172

Muitas pessoas mencionaram que "os objetos não podem ser classificados" , mas depois disso eles estão fornecendo uma solução que funciona. Paradoxo, não é?

Ninguém menciona por que essas soluções estão funcionando. Eles são, porque na maioria das implementações do navegador, os valores nos objetos são armazenados na ordem em que foram adicionados. É por isso que se você criar um novo objeto a partir da lista ordenada de chaves, ele retornará um resultado esperado.

E acho que poderíamos adicionar mais uma solução - a maneira funcional do ES5:

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

Versão ES2015 acima (formatada para "uma linha"):

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

Breve explicação dos exemplos acima (conforme solicitado nos comentários):

Object.keysestá nos dando uma lista de chaves no objeto fornecido ( objou o), depois classificamos as que usam o algoritmo de classificação padrão. Em seguida, .reduceé usado para converter essa matriz novamente em um objeto, mas desta vez com todas as chaves classificadas.

nome de código-
fonte
7
@Pointy Esse comportamento sempre está disponível em todos os principais navegadores e foi padronizado no ES6 / ES2015 . Eu diria que este é um bom conselho.
Mathias Bynens
3
Essa é a maneira mais simples e concisa de realizar tarefas no EcmaScript v5. Um pouco atrasado para a festa, mas deve ser a resposta aceita.
Steven de Salas
2
"Eles são, porque na maioria das implementações do navegador, os valores nos objetos são armazenados na ordem em que foram adicionados" Somente para propriedades não numéricas. Observe também que ainda não há garantia em que ordem as propriedades são iteradas (por exemplo, via for...in).
Felix Kling
2
Foi muito gentil da sua parte explicar por que está funcionando. Ele fez a lição para mim. Obrigado!
ola
5
Meu interlocutor reclamou dessa frase (retornando uma tarefa), mas esta funciona para mim e é mais fácil para mim ler:Object.keys(dict).sort().reduce((r, k) => Object.assign(r, { [k]: dict[k] }), {});
aks.
68

Gente, estou figurativamente chocado! Claro que todas as respostas são um pouco antigas, mas ninguém sequer mencionou a estabilidade na classificação! Então, fique comigo, vou tentar o meu melhor para responder à pergunta em si e entrar em detalhes aqui. Então, vou pedir desculpas agora, será muito para ler.

Como em 2018, usarei apenas o ES6, os Polyfills estão disponíveis nos documentos MDN, os quais vincularemos na parte especificada.


Responda a pergunta:

Se suas chaves são apenas números, então você pode usar com segurança Object.keys()juntamente com Array.prototype.reduce()a devolver o objeto ordenada:

// 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), {}));

No entanto, se você estiver trabalhando com strings, recomendo encadear Array.prototype.sort()tudo isso:

// 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), {}));

Se alguém está se perguntando o que reduz:

// 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().
}, {});

Se necessário, aqui está a explicação para o liner:

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

Por que a classificação é um pouco complicada:

Em resumo Object.keys(), retornará uma matriz com a mesma ordem que obtemos com um loop normal:

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

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

Object.keys () retorna uma matriz cujos elementos são cadeias correspondentes às propriedades enumeráveis ​​encontradas diretamente no objeto. A ordem das propriedades é a mesma que a especificada repetindo as propriedades do objeto manualmente.

Sidenote - você também pode usar Object.keys()matrizes, lembre-se de que o índice será retornado:

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

Mas não é tão fácil como mostrado nesses exemplos: objetos do mundo real podem conter números e caracteres alfabéticos ou até símbolos (por favor, não faça isso).

Aqui está um exemplo com todos eles em um objeto:

// 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' ]

Agora, se usarmos Array.prototype.sort()na matriz acima, a saída será alterada:

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

Aqui está uma citação dos documentos:

O método sort () classifica os elementos de uma matriz no local e retorna a matriz. O tipo não é necessariamente estável. A ordem de classificação padrão é de acordo com os pontos de código Unicode da sequência.

A complexidade de tempo e espaço da classificação não pode ser garantida, pois depende da implementação.

Você precisa garantir que um deles retorne a saída desejada para você. Nos exemplos da vida real, as pessoas tendem a misturar as coisas especialmente se você usar diferentes entradas de informações, como APIs e bancos de dados.


Então, qual é o grande problema?

Bem, existem dois artigos que todo programador deve entender:

Algoritmo no local :

Na ciência da computação, um algoritmo no local é um algoritmo que transforma a entrada usando nenhuma estrutura de dados auxiliar. No entanto, uma pequena quantidade de espaço de armazenamento extra é permitida para variáveis ​​auxiliares. A entrada geralmente é substituída pela saída à medida que o algoritmo é executado. O algoritmo in-loco atualiza a sequência de entrada apenas através da substituição ou troca de elementos. Um algoritmo que não está no local é chamado às vezes não no local ou fora do local.

Então, basicamente, nossa matriz antiga será substituída! Isso é importante se você deseja manter a matriz antiga por outros motivos. Portanto, mantenha isso em mente.

Algoritmo de classificação

Os algoritmos de classificação estável classificam elementos idênticos na mesma ordem em que aparecem na entrada. Ao classificar alguns tipos de dados, apenas parte dos dados é examinada ao determinar a ordem de classificação. Por exemplo, no exemplo de classificação de cartas à direita, as cartas estão sendo classificadas por sua classificação e seu naipe é ignorado. Isso permite a possibilidade de várias versões diferentes e ordenadas corretamente da lista original. Os algoritmos de classificação estável escolhem um destes, de acordo com a regra a seguir: se dois itens forem comparados como iguais, como os dois 5 cartões, sua ordem relativa será preservada, de modo que, se um veio antes do outro na entrada, ele também será vem antes do outro na saída.

insira a descrição da imagem aqui

Um exemplo de classificação estável em cartas de baralho. Quando as cartas são classificadas por classificação com uma classificação estável, os dois 5s devem permanecer na mesma ordem na saída classificada em que estavam originalmente. Quando são classificadas com uma classificação não estável, os 5s podem terminar no oposto ordem na saída classificada.

Isso mostra que a classificação está correta, mas mudou. Portanto, no mundo real, mesmo que a classificação esteja correta, temos que garantir o que esperamos! Isso é super importante, lembre-se disso também. Para obter mais exemplos de JavaScript, consulte Array.prototype.sort () - docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Megajin
fonte
3
Você joga rock, obrigado por esta resposta incrível. Um dos melhores que eu já vi no SO. Felicidades.
Gavin
Se você pudesse fornecer um método assustador para usar no final. Ótima resposta!
mmm
@ momomo o problema é que, dependendo do que você espera da classificação, não existe um método correto. No entanto, você pode simplesmente usar este pedaço de código de minha resposta: Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}).
Megajin 22/02/19
A estabilidade do tipo não é aplicável a esta pergunta: estamos classificando por chave de objeto, e a chave é única. (Para estender o exemplo da sua carta: nunca pode haver dois 5s no baralho, mesmo que sejam de naipes diferentes.)
Darren Cook
@DarrenCook good question! Você está certo de que nunca haverá a mesma chave em um objeto. No entanto, a estabilidade é mais complexa do que apenas a exclusividade de uma chave. Na maioria das vezes, uma matriz é incluída na classificação de objetos. E é aí que tudo pode se tornar instável. Imagine um jogo de cartas com 5 jogadores. Cada mão é representada por uma matriz (para manter uma mão individual) e os cartões como objetos. Se o seu cartão estiver assim {5: 'hearts'}ou {5: 'spades'}você começar a classificar o array, ele se tornará potencialmente instável em jogos como o rummy. Para não falar de idiomas diferentes.
Megajin 28/01
29

Isso funciona para mim

/**
 * 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;
};
Ashit Vora
fonte
10
Esta é realmente a resposta correta para a pergunta em questão. Para uma versão simplificada usando o Underscore, consulte: jsfiddle.net/wPjaQ/1
radicand
6
@radicand Não, esta resposta não está correta. Ele retorna um novo objeto, que também não tem ordem.
Paul
3
@radicand Na prática também não. Não existe ordem nas chaves dos objetos, então como você pode dizer que, na prática, isso fornece um objeto na ordem classificada? Realmente apenas devolve uma cópia rasa do objeto pelo qual você passa. #
Paul
9
Isso é super errado. Pode funcionar por enquanto, mas será interrompido em um navegador da Web diferente ou em um carregamento de página diferente no mesmo navegador. Os navegadores podem selecionar aleatoriamente chaves de objeto por segurança ou, à medida que você preenche um objeto, ele coloca os valores em diferentes intervalos de memória, dependendo das chaves, o que retornará uma ordem diferente. Se isso funcionar, é apenas uma sorte para você.
Yobert
11
Ele também tem um uso desnecessário de jQuery.
RobG 01/12/19
25

É 2019 e temos uma maneira 2019 de resolver isso :)

Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())
Ben
fonte
2
Como classificamos objetos aninhados por chave?
A2441918 #
@ a2441918 Da mesma maneira que você faria com a função sort (). Dê uma olhada: developer.mozilla.org/de/docs/Web/JavaScript/Reference/… Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). Sort ((k, j ) => k - j))
#
Para usuários do TypeScript, isso ainda não está disponível para nós, consulte: github.com/microsoft/TypeScript/issues/30933
tsujp
One-liner legal, mas como classificar as chaves de uma maneira que não diferencia maiúsculas de minúsculas?
theMaxx 22/03
1
@theMaxx Use uma função personalizada para classificação, algo como: `` `Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). sort (([key1, val1], [key2, val2]) => key1.toLowerCase (). localeCompare (key2.toLowerCase ()))) ``
Ben
22

aqui está o forro 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), {} ));

sravan ganji
fonte
Que diabos é essa sintaxe maluca? (o[k] = v, o). Por que isso funciona, onde posso encontrar documentos sobre isso? Obviamente, ele retorna o parâmetro mais à direita, mas por quê?
ntaso 9/07/19
1
@ntaso aqui
James
short função de primeiro faz o[k]igual a ve retornao
Tahsin Turkoz
19

Esta é uma pergunta antiga, mas seguindo a sugestão da resposta de Mathias Bynens, fiz uma versão curta para classificar o objeto atual , sem muita sobrecarga.

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

após a execução do código, o próprio objeto "não ordenado" terá as chaves classificadas em ordem alfabética.

Sergio Moura
fonte
17

Usando o lodash, isso funcionará:

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

Apenas comida para pensar.

Brian M. Hunt
fonte
15

Suponha que possa ser útil no depurador do VisualStudio, que mostra propriedades não ordenadas do objeto.

(function(s){var t={};Object.keys(s).sort().forEach(function(k){t[k]=s[k]});return t})({b:2,a:1,c:3})
Serg
fonte
Tão grande obrigado loooot
Mugiwara
Agradável! Obrigado por esta solução sucinta.
Con Antonakos
9

Versão sublinhada :

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

Se você não confiar no seu navegador para manter a ordem das chaves, sugiro que confie em uma matriz ordenada de matrizes emparelhadas com valor-chave.

_.sortBy(_.pairs(c),function(o){return o[0]})
Flavien Volken
fonte
Melhor:_.object(_.sortBy(_.pairs(unordered), _.first))
Afanasii Kurakin 24/04/19
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,
});
user3286817
fonte
Talvez seja melhor adicionar alguma explicação do seu código.
Aristotll
1
Obtém as chaves do objeto, por isso é uma matriz de seqüências de caracteres, eu as classifico () e, como é uma matriz de seqüências de caracteres (chaves), eu as reduzo (com reduzir () da matriz js). O acc inicialmente é um objeto vazio {} (último argumento do redutor) e o redutor (retorno de chamada) atribui ao objeto vazio os valores do objeto de origem com a sequência de teclas ordenada.
user3286817
8

Talvez uma forma um pouco mais elegante:

 /**
     * 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 e o mesmo com a sintaxe ES6 +:

function ksort( src ) {
  const keys = Object.keys( src );
  keys.sort();
  return keys.reduce(( target, key ) => {
        target[ key ] = src[ key ];
        return target;
  }, {});
};
Dmitry Sheiko
fonte
não classifica nada. você ainda está retornando um objeto. você não pode garantir que os objetos em seu destino realmente tenham alguma ordem. você precisa retornar uma matriz. jeeezus.
mmm
a única coisa que você está fazendo aqui é garantir que seja um conjunto, de uma maneira não ideal.
mmm
7

classificação recursiva, para objetos e matrizes aninhados

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!'
            }
        },
    ]
});
user3286817
fonte
Eu acho que você precisa de uma elselá - poderia ser verdade para ambos Array.isArray(obj[key])e paratypeof obj[key] === 'object'
jononomo
Quando você tem uma matriz de primitivas, sua função transforma as primitivas (string / número) em objetos vazios. Para entender isso, adicionei o seguinte logo no início da sua função function sortObjectKeys(obj){:: if(typeof obj != 'object'){ /* it is a primitive: number/string (in an array) */ return obj; }. Para maior robustez, no início completo, também adicionei:if(obj == null || obj == undefined){ return obj; }
alterado em
4

Como já mencionado, os objetos não são ordenados.

Contudo...

Você pode achar útil esse idioma:

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

var kv = [];

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

kv.sort()

Você pode iterar através de kv e fazer o que quiser.

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

Aqui está uma versão limpa baseada em lodash que funciona com objetos aninhados

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

Seria ainda mais limpo se o lodash tivesse um toObject()método ...

BlueRaja - Danny Pflughoeft
fonte
3

Basta usar o lodash para descompactar o mapa e classificar. Pelo primeiro valor do par e zip novamente, ele retornará a chave classificada.

Se você deseja classificar o valor, altere o índice do par para 1 em vez de 0

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

insira a descrição da imagem aqui

Narayanaperumal Gurusamy
fonte
Por favor, use o link editar para explicar como esse código funciona e não forneça apenas o código, pois é mais provável que uma explicação ajude futuros leitores. Veja também Como responder . fonte
Jed Fox
3

Classifica chaves recursivamente enquanto preserva as referências.

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

Exemplo:

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}
brunettdan
fonte
Bom trecho! Qual é o propósito de delete o[e[0]];lá? Não podemos simplesmente atribuir?
Boyang
Parece que apenas novas atribuições para chaves inexistentes anexarão a chave no final. Se a exclusão for comentada, as chaves não serão classificadas, pelo menos não no Chrome.
Brunettdan # 20/18
isso faz sentido. Obrigado! De qualquer forma, essa é uma causa perdida, porque as chaves do objeto js não têm sequência, de acordo com as especificações. Estamos apenas explorando obj e log função detalhes Impl
Boyang
Sim, eu uso o mapa quando a ordem de chaves são importantes: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
brunettdan
3
Object.keys(unordered).sort().reduce(
    (acc,curr) => ({...acc, [curr]:unordered[curr]})
    , {}
)
Wildhammer
fonte
3

Esta é uma solução leve para tudo o que preciso para a classificação 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;
    }, {});
}
Alan Hape
fonte
2

Use esse código se você tiver objetos aninhados ou se tiver objetos de matriz aninhados.

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;
};
Phani Reddy
fonte
5
O autor não afirma que está usando jQuery, nem a pergunta está marcada com jQuery. Seria bom se você adicionar uma solução em javascript puro.
Rusmus 25/02/14
Graças @Phani este é exatamente o que eu precisava
Will Sheppard
2

Solução:

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

Explicação:

Muitos tempos de execução do JavaScript armazenam valores dentro de um objeto na ordem em que são adicionados.

Para classificar as propriedades de um objeto por suas chaves, você pode usar a função Object.keys que retornará uma matriz de chaves. A matriz de chaves pode ser classificada pelo Array.prototype.sort () método que classifica os elementos de uma matriz no local (não é necessário atribuí-los a uma nova variável).

Depois que as chaves são classificadas, você pode começar a usá-las uma a uma para acessar o conteúdo do objeto antigo e preencher um novo objeto (que agora está classificado).

Abaixo está um exemplo do procedimento (você pode testá-lo nos navegadores de destino):

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

Nota: Object.keys é um método ECMAScript 5.1, mas aqui está um polyfill para navegadores mais antigos:

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;
  };
}
Benny Neugebauer
fonte
2

Transferi algumas enumerações Java para objetos javascript.

Esses objetos retornaram matrizes corretas para mim. se as chaves do objeto são do tipo misto (string, int, char), há um problema.

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"]
Sherali Turdiyev
fonte
2

Fragmento simples e legível, usando lodash.

Você precisa colocar a chave entre aspas apenas ao chamar sortBy. Ele não precisa estar entre aspas nos próprios dados.

_.sortBy(myObj, "key")

Além disso, seu segundo parâmetro para mapear está errado. Deve ser uma função, mas o uso de arrancar é mais fácil.

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

Há um ótimo projeto de @sindresorhus chamado sort-keys que funciona de maneira incrível.

Você pode verificar seu código fonte aqui:

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

Ou você pode usá-lo com o npm:

$ npm install --save sort-keys

Aqui também estão exemplos de código de seu leia-me

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}
fernandopasik
fonte
1

Resposta JavaScript pura para classificar um Objeto. Esta é a única resposta que conheço que manipulará números negativos. Esta função é para classificar objetos numéricos.

Objeto de entrada = {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;
}

A saída será um objeto classificado por esses números com novas chaves começando em 0.

Caso
fonte
1

Apenas para simplificá-lo e deixar mais clara a resposta de Matt Ball

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

João Pimentel Ferreira
fonte
1

Não tenho certeza se isso responde à pergunta, mas é disso que eu precisava.

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

Chamado como:

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

A única linha:

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

a melhor maneira de fazer isso é

 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 ()

Você pode primeiro converter seu objeto quase do tipo matriz em uma matriz real e, em seguida, usar .reverse ():

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

O slot vazio no final se causa porque o seu primeiro índice é 1 em vez de 0. Você pode remover o slot vazio com .length-- ou .pop ().

Como alternativa, se você deseja emprestar .reverse e chamá-lo no mesmo objeto, ele deve ser um objeto totalmente do tipo matriz. Ou seja, ele precisa de uma propriedade length:

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

Observe que ele retornará o mesmo objeto de objeto totalmente de matriz, portanto não será uma matriz real. Você pode usar delete para remover a propriedade length.

Pedro JR
fonte