Trier l'objet JavaScript par clé

532

J'ai besoin de trier les objets JavaScript par clé.

D'où ce qui suit:

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

Deviendrait:

{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }
vdh_ant
la source
3
doublon possible du tri d'un objet JSON en Javascript
Abraham
39
En 2011 (lorsque cette question a été publiée), la spécification ECMAScript a déclaré que les objets JavaScript n'ont pas d'ordre inhérent - l'ordre observé dépendait de l'implémentation et ne pouvait donc pas être invoqué. Cependant, il s'avère que tous les moteurs JavaScript implémentent plus ou moins la même sémantique, donc ceux-ci ont maintenant été standardisés dans ES6 . Par conséquent, la plupart des réponses ci-dessous étaient correctes selon les spécifications, mais sont désormais incorrectes.
Mathias Bynens
dire brièvement utiliser trié stringify lorsque vous devez comparer ou hacher les résultats: npmjs.com/package/json-stable-stringify
exebook
Étant donné que les objets ne sont que des cartes ou des dictés en fonction de votre langue, il y a peu ou pas de raison de le faire. CELA ÊTRE DIT, Généralement, l'ordre dans lequel ils sont injectés dans une carte est en fait l'ordre dans lequel ils résident lors de la stringification. Donc, si vous avez créé une nouvelle carte et des valeurs attribuées en fonction d'une liste de clés présélectionnée, vous vous trouverez une carte ordonnée en fonction des clés
Fallenreaper
Notez que depuis Object.entrieset Object.fromEntriesont été ajoutés à JS, cela peut être réalisé avec une doublure bien courte:Object.fromEntries(Object.entries(obj).sort())
Mike 'Pomax' Kamermans

Réponses:

472

Les autres réponses à cette question sont dépassées, n'ont jamais correspondu à la réalité de la mise en œuvre et sont officiellement devenues incorrectes maintenant que la spécification ES6 / ES2015 a été publiée.


Voir la section sur l' ordre d'itération des propriétés dans Exploration ES6 par Axel Rauschmayer :

Toutes les méthodes qui itèrent sur les clés de propriété le font dans le même ordre:

  1. Tout d'abord tous les indices Array, triés numériquement.
  2. Ensuite, toutes les clés de chaîne (qui ne sont pas des index), dans l'ordre dans lequel elles ont été créées.
  3. Ensuite, tous les symboles, dans l'ordre dans lequel ils ont été créés.

Alors oui, les objets JavaScript sont en fait ordonnés et l'ordre de leurs clés / propriétés peut être modifié.

Voici comment trier un objet par ses clés / propriétés, par ordre alphabétique:

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

Utilisez varau lieu de constpour la compatibilité avec les moteurs ES5.

Mathias Bynens
la source
5
Je ne vois vraiment pas de différence avec votre code et la meilleure réponse ici, à part l'utilisation d'une technique de boucle légèrement différente. La question de savoir si les objets peuvent ou non être «commandés» semble non pertinente. La réponse à cette question est toujours la même. Les spécifications publiées ne font que confirmer les réponses ici.
Phil
6
Pour info, il a été précisé que l' ordre d' énumération des propriétés n'est toujours pas défini: esdiscuss.org/topic/…
Felix Kling
6
@ Phil_1984_ Cette réponse et la réponse la mieux notée sont très différentes. La question d'OP était de savoir comment trier un objet littéral. La réponse la plus votée indique que vous ne pouvez pas, puis propose une solution de contournement en stockant les clés triées dans un tableau, puis en itérant et en imprimant les paires de valeurs de clés à partir du tableau trié. Cette réponse affirme que l'ordre des littéraux d'objet est désormais triable et son exemple stocke les valeurs de clé triées dans un littéral d'objet, puis imprime directement l'objet trié. En passant, ce serait bien si le site lié existait toujours.
cchamberlain
6
Les deux réponses utilisent simplement la fonction Array.sort pour trier les clés en premier. L'OP demande de trier un "objet JavaScript" et utilise simplement la notation d'objet JavaScript (JSON) pour décrire les 2 objets. Ces 2 objets sont logiquement identiques, ce qui signifie que le tri n'est pas pertinent. Je pense que la meilleure réponse explique cela beaucoup mieux. Dire "toutes les autres réponses sont maintenant officiellement incorrectes" est trop extrême pour moi, surtout avec un lien brisé. Je pense que le problème est que "cette nouvelle spécification ES6" donne l'illusion que les objets Javascript ont une liste ordonnée de clés, ce qui n'est tout simplement pas vrai.
Phil
1
Veuillez ajouter que cette solution n'est pas prise en charge par une variété de navigateurs modernes (google "caniuse ES6"). L'utilisation de ces réponses risque de ne pas trouver de bogues difficiles à trouver dans certains navigateurs (par exemple, Safari lorsque Chrome va bien).
Manuel Arwed Schmidt,
244

Les objets JavaScript 1 ne sont pas commandés. Cela n'a aucun sens d'essayer de les "trier". Si vous souhaitez parcourir les propriétés d'un objet, vous pouvez trier les clés, puis récupérer les valeurs associées:

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.keysMise en œuvre alternative utilisant la fantaisie:

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 Ne pas être pédant, mais un objet JSON n'existe pas .

Matt Ball
la source
2
@MarcelKorpel Il existe un objet JSON. Consultez la section 8 du RFC JSON officiel: ietf.org/rfc/rfc4627.txt
Paul
8
@Paulpro deux choses à noter à propos de ce RFC: d'abord, il a 7 ans à ce stade, et le vocabulaire change avec le temps; deuxièmement, "Ce mémo fournit des informations à la communauté Internet. Il ne spécifie aucune norme Internet d'aucune sorte." Le fait qu'une séquence de caractères donnée représente un littéral d'objet JavaScript ou un texte JSON dépend du contexte / de l'utilisation. Le terme «objet JSON» se confond et rend la distinction ambiguë de manière préjudiciable. Débarrassons-nous de la terminologie imprécise et utilisons le terme le plus précis possible. Je ne vois aucune raison de faire autrement. Les mots comptent.
Matt Ball
6
@MattBall IMO JSON Object est un terme très précis pour une chaîne comme {"a", 1}tout comme JSON Array est un terme précis pour une chaîne comme [1]. Il est utile de pouvoir communiquer en disant des choses comme le troisième objet de mon tableau lorsque vous avez la chaîne [{x: 1}, {y: 2}, {z: 3}], donc je préfère de beaucoup "Ce n'est pas un objet JSON" lorsque vous commentez un littéral Javascript, plutôt que "Il n'y en a pas chose en tant qu'objet JSON ", ce qui va juste causer plus de confusion et de difficultés de communication plus tard lorsque l'OP fonctionne réellement avec JSON.
Paul
3
@Paulpro, je dois être en désaccord. {"a", 1}est soit un littéral objet, soit un texte JSON (alias chaîne JSON, si vous préférez vraiment). Le choix dépend du contexte, le premier s'il apparaît textuellement dans le code source JavaScript, le second s'il s'agit d'une chaîne qui doit être transmise à un analyseur JSON pour être utilisée plus loin. Il existe de réelles différences entre les deux en ce qui concerne la syntaxe autorisée, l'utilisation correcte et la sérialisation.
Matt Ball
4
Maintenant que ES6 / ES2015 est finalisé, cette réponse est officiellement devenue incorrecte. Voir ma réponse pour plus d'informations.
Mathias Bynens
172

Beaucoup de gens ont mentionné que "les objets ne peuvent pas être triés" , mais après cela, ils vous donnent une solution qui fonctionne. Paradoxe, n'est-ce pas?

Personne ne mentionne pourquoi ces solutions fonctionnent. Ils le sont, car dans la plupart des implémentations du navigateur, les valeurs des objets sont stockées dans l'ordre dans lequel elles ont été ajoutées. C'est pourquoi si vous créez un nouvel objet à partir d'une liste triée de clés, cela renvoie un résultat attendu.

Et je pense que nous pourrions ajouter une autre solution - la manière fonctionnelle ES5:

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

Version ES2015 ci-dessus (formatée en "one-liner"):

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

Brève explication des exemples ci-dessus (comme demandé dans les commentaires):

Object.keysnous donne une liste de clés dans l'objet fourni ( objou o), puis nous trions celles qui utilisent l'algorithme de tri par défaut, la prochaine .reduceest utilisée pour reconvertir ce tableau en objet, mais cette fois avec toutes les clés triées.

nom de code-
la source
7
@Pointy Ce comportement a toujours été disponible dans tous les principaux navigateurs et a été normalisé dans ES6 / ES2015 . Je dirais que c'est un bon conseil.
Mathias Bynens
3
Il s'agit de la manière la plus simple et la plus concise d'accomplir une tâche dans EcmaScript v5. Un peu tard pour la fête mais ça devrait être la réponse acceptée.
Steven de Salas
2
"Ils le sont, car dans la plupart des implémentations du navigateur, les valeurs dans les objets sont stockées dans l'ordre dans lequel elles ont été ajoutées" Uniquement pour les propriétés non numériques. Notez également qu'il n'y a toujours aucune garantie dans quel ordre les propriétés sont itérées (par exemple via for...in).
Felix Kling
2
Ravi de vous expliquer pourquoi ça marche, ça a fait la leçon pour moi. Merci!
ola
5
Mon linter s'est plaint de ce one-liner (renvoyant une affectation), mais celui-ci fonctionne pour moi et est plus facile à lire pour moi:Object.keys(dict).sort().reduce((r, k) => Object.assign(r, { [k]: dict[k] }), {});
aks.
68

Les gars, je suis choqué au figuré! Bien sûr, toutes les réponses sont un peu anciennes, mais personne n'a même mentionné la stabilité du tri! Alors soyez indulgents, je ferai de mon mieux pour répondre à la question elle-même et entrer dans les détails ici. Je vais donc m'excuser maintenant, ce sera beaucoup à lire.

Comme c'est 2018, je n'utiliserai que ES6, les Polyfills sont tous disponibles sur la documentation MDN, que je lierai à la partie donnée.


Réponse à la question:

Si vos clés ne sont que des chiffres, vous pouvez les utiliser en toute sécurité Object.keys()avec Array.prototype.reduce()pour renvoyer l'objet trié:

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

Cependant, si vous travaillez avec des chaînes, je recommande fortement d'enchaîner Array.prototype.sort()tout cela:

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

Si quelqu'un se demande ce que fait réduire:

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

Si nécessaire, voici l'explication de la doublure:

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

Pourquoi le tri est un peu compliqué:

En bref Object.keys()retournera un tableau avec le même ordre que celui que nous obtenons avec une boucle normale:

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

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

Object.keys () renvoie un tableau dont les éléments sont des chaînes correspondant aux propriétés énumérables trouvées directement sur l'objet. L'ordre des propriétés est le même que celui donné en bouclant manuellement les propriétés de l'objet.

Sidenote - vous pouvez également l'utiliser Object.keys()sur des tableaux, gardez à l'esprit que l'index sera retourné:

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

Mais ce n'est pas aussi facile que le montrent ces exemples, les objets du monde réel peuvent contenir des chiffres et des caractères alphabétiques ou même des symboles (veuillez ne pas le faire).

Voici un exemple avec tous dans un seul objet:

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

Maintenant, si nous utilisons Array.prototype.sort()sur le tableau ci-dessus, les modifications de sortie:

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

Voici une citation de la documentation:

La méthode sort () trie les éléments d'un tableau en place et retourne le tableau. Le tri n'est pas nécessairement stable. L'ordre de tri par défaut est en fonction des points de code Unicode de la chaîne.

La complexité temporelle et spatiale du tri ne peut pas être garantie car elle dépend de l'implémentation.

Vous devez vous assurer que l'un d'eux renvoie la sortie souhaitée pour vous. Dans des exemples réels, les gens ont tendance à mélanger les choses, surtout si vous utilisez ensemble différentes entrées d'informations telles que les API et les bases de données.


Alors, quel est le gros problème?

Eh bien, il y a deux articles que chaque programmeur doit comprendre:

Algorithme sur place :

En informatique, un algorithme sur place est un algorithme qui transforme l'entrée sans utiliser de structure de données auxiliaire. Cependant, une petite quantité d'espace de stockage supplémentaire est autorisée pour les variables auxiliaires. L'entrée est généralement remplacée par la sortie lors de l'exécution de l'algorithme. L'algorithme sur place met à jour la séquence d'entrée uniquement par remplacement ou échange d'éléments. Un algorithme qui n'est pas en place est parfois appelé non en place ou hors place.

Donc, fondamentalement, notre ancien tableau sera écrasé! Ceci est important si vous souhaitez conserver l'ancien tableau pour d'autres raisons. Gardez cela à l'esprit.

Algorithme de tri

Les algorithmes de tri stables trient les éléments identiques dans le même ordre qu'ils apparaissent dans l'entrée. Lors du tri de certains types de données, seule une partie des données est examinée lors de la détermination de l'ordre de tri. Par exemple, dans l'exemple de tri des cartes à droite, les cartes sont triées selon leur rang et leur couleur est ignorée. Cela permet la possibilité de plusieurs versions différentes correctement triées de la liste d'origine. Les algorithmes de tri stables choisissent l'un d'eux, selon la règle suivante: si deux éléments se comparent comme égaux, comme les deux 5 cartes, alors leur ordre relatif sera préservé, de sorte que si l'un précède l'autre dans l'entrée, il sera également venir avant l'autre dans la sortie.

entrez la description de l'image ici

Un exemple de tri stable sur les cartes à jouer. Lorsque les cartes sont triées par rang avec un tri stable, les deux 5 doivent rester dans le même ordre dans la sortie triée dans laquelle ils étaient à l'origine. Lorsqu'elles sont triées avec un tri non stable, les 5 peuvent finir dans le sens opposé ordre dans la sortie triée.

Cela montre que le tri est correct mais qu'il a changé. Donc dans le monde réel, même si le tri est correct, nous devons nous assurer que nous obtenons ce que nous attendons! C'est très important, gardez cela à l'esprit également. Pour plus d'exemples JavaScript, examinez Array.prototype.sort () - docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

Megajin
la source
3
Vous flippin rock, merci pour cette réponse incroyable. L'un des meilleurs que j'ai vu sur SO. À votre santé.
Gavin
Si seulement vous pouviez fournir une méthode effrayante à utiliser à la fin. Bonne réponse cependant!
mmm
@momomo le problème est que, selon ce que vous attendez du tri, il n'y a pas de bonne méthode. Cependant , vous pouvez simplement utiliser ce morceau de code de ma réponse: Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}).
Megajin
La stabilité du tri n'est-elle pas applicable à cette question: nous trions par clé d'objet, et la clé est unique. (Pour prolonger votre exemple de carte: il ne peut jamais y avoir deux 5 dans le pack, même s'ils sont de couleurs différentes.)
Darren Cook
@DarrenCook bonne question! Vous avez raison, il n'y aura jamais la même clé dans un même objet. Cependant, la stabilité est plus complexe que le caractère unique d'une clé. La plupart du temps, un tableau est inclus dans le tri des objets. Et c'est là que tout peut devenir instable. Imaginez un jeu de cartes avec 5 joueurs. Chaque main est représentée par un tableau (pour conserver un tri individuel des mains) et les cartes en tant qu'objets. Si votre carte ressemble à ceci {5: 'hearts'}ou si {5: 'spades'}vous commencez à trier le tableau, il deviendra potentiellement instable dans des jeux comme le rami. Sans parler de langues différentes.
Megajin
29

Ça marche pour moi

/**
 * 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
la source
10
C'est en fait la bonne réponse à la question posée. Pour une version simplifiée utilisant Underscore, voir: jsfiddle.net/wPjaQ/1
radicand
6
@radicand Non, cette réponse n'est pas correcte. Il renvoie un nouvel objet, qui n'a également aucun ordre.
Paul
3
@radicand Cela ne fonctionne pas non plus. L'ordre sur les clés des objets n'existe pas, alors comment pouvez-vous dire qu'en pratique cela vous donne un objet dans l'ordre trié? Cela vous rend vraiment juste une copie superficielle de l'objet que vous passez.
Paul
9
C'est super faux. Il se peut que cela fonctionne pour l'instant, mais il se brisera dans un autre navigateur Web ou une autre charge de page dans le même navigateur. Les navigateurs peuvent randomiser les clés d'objet pour des raisons de sécurité, ou lorsque vous remplissez un objet, il placera les valeurs dans différents compartiments de mémoire en fonction des clés, ce qui renverra un ordre différent. Si cela fonctionne, c'est juste de la chance pour vous.
Yobert
11
Il a également une utilisation inutile de jQuery.
RobG
25

Nous sommes en 2019 et nous avons un moyen de résoudre ce problème en 2019 :)

Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())
Ben
la source
2
Comment trier les objets imbriqués par clé?
a2441918
@ a2441918 De la même manière que vous le feriez avec la fonction sort (). Jetez un œil: developer.mozilla.org/de/docs/Web/JavaScript/Reference/… Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). Sort ((k, j ) => k - j))
user2912903
Pour les utilisateurs de TypeScript, cela n'est pas encore disponible pour nous, voir: github.com/microsoft/TypeScript/issues/30933
tsujp
Nice one-liner, mais comment trier les clés de manière insensible à la casse?
theMaxx
1
@theMaxx Utilisez une fonction personnalisée pour le tri, quelque chose comme: `` `Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). sort (([key1, val1], [key2, val2]) => key1.toLowerCase (). localeCompare (key2.toLowerCase ()))) ``
Ben
22

voici le 1 liner

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
la source
Qu'est-ce que c'est que cette syntaxe folle? (o[k] = v, o). Pourquoi cela fonctionne-t-il même, où puis-je trouver des documents à ce sujet? Il renvoie évidemment le paramètre le plus à droite, mais pourquoi?
ntaso
1
@ntaso ici
James
fonction courte fait d'abord o[k]égal à vpuis reviento
Tahsin Turkoz
19

C'est une vieille question, mais en s'inspirant de la réponse de Mathias Bynens, j'ai fait une version courte pour trier l' objet actuel , sans trop de surcharge.

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

après l'exécution du code, l'objet "non ordonné" lui-même verra les clés triées alphabétiquement.

Sergio Moura
la source
17

En utilisant lodash, cela fonctionnera:

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

Juste matière à réflexion.

Brian M. Hunt
la source
15

Supposons qu'il puisse être utile dans le débogueur VisualStudio qui affiche les propriétés d'objet non ordonnées.

(function(s){var t={};Object.keys(s).sort().forEach(function(k){t[k]=s[k]});return t})({b:2,a:1,c:3})
Serg
la source
Merci beaucoup un loooot
Mugiwara
Agréable! Merci pour cette solution succincte.
Con Antonakos
9

Version de soulignement :

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

Si vous ne faites pas confiance à votre navigateur pour conserver l'ordre des clés, je vous suggère fortement de vous fier à un tableau ordonné de tableaux de paires clé-valeur.

_.sortBy(_.pairs(c),function(o){return o[0]})
Flavien Volken
la source
Mieux:_.object(_.sortBy(_.pairs(unordered), _.first))
Afanasii Kurakin
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
la source
Il est peut-être préférable d'ajouter des explications sur votre code.
aristotll
1
Obtient les clés de l'objet, c'est donc un tableau de chaînes, je les trie () et comme c'est un tableau de chaînes (clés), je les réduit (avec Reduce () de js Array). L'acc est initialement un objet vide {} (dernier argument du réducteur) et le réducteur (rappel) affecte à l'objet vide les valeurs de l'obj source avec la séquence de touches ordonnée.
user3286817
8

Peut-être une forme un peu plus élégante:

 /**
     * 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 et même avec la syntaxe ES6 +:

function ksort( src ) {
  const keys = Object.keys( src );
  keys.sort();
  return keys.reduce(( target, key ) => {
        target[ key ] = src[ key ];
        return target;
  }, {});
};
Dmitry Sheiko
la source
ça ne trie rien. vous renvoyez toujours un objet. vous ne pouvez pas garantir que les objets de votre cible auront réellement un ordre. vous devez renvoyer un tableau. jeeezus.
mmm
la seule chose que vous faites ici est de vous assurer qu'il s'agit d'un ensemble, de manière non optimale.
mmm
7

tri récursif, pour les objets imbriqués et les tableaux

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
la source
Je pense que vous en avez besoin else- pourrait être vrai pour les deux Array.isArray(obj[key])et pourtypeof obj[key] === 'object'
jononomo
Lorsque vous disposez d'un tableau de primitives, votre fonction transforme les primitives (chaîne / nombre) en objets vides. Pour attraper cela, j'ai ajouté ce qui suit juste au début de votre fonction function sortObjectKeys(obj){:: if(typeof obj != 'object'){ /* it is a primitive: number/string (in an array) */ return obj; }. Pour plus de robustesse, j'ai également ajouté au démarrage complet:if(obj == null || obj == undefined){ return obj; }
isgoed
4

Comme déjà mentionné, les objets ne sont pas classés.

Toutefois...

Vous pouvez trouver cet idiome utile:

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

var kv = [];

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

kv.sort()

Vous pouvez ensuite parcourir le kv et faire ce que vous voulez.

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

Voici une version propre basée sur lodash qui fonctionne avec des objets imbriqués

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

Ce serait encore plus propre si lodash avait une toObject()méthode ...

BlueRaja - Danny Pflughoeft
la source
3

Utilisez simplement lodash pour décompresser la carte et trier par la première valeur de pair et zip à nouveau, il renverra la clé triée.

Si vous voulez que l'index de paire de valeurs triées soit à 1 au lieu de 0

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

entrez la description de l'image ici

Narayanaperumal Gurusamy
la source
Veuillez utiliser le lien d' édition pour expliquer comment ce code fonctionne et ne pas simplement donner le code, car une explication est plus susceptible d'aider les futurs lecteurs. Voir aussi Comment répondre . source
Jed Fox
3

Trie les clés de manière récursive tout en préservant les références.

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

Exemple:

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
la source
Un bel extrait! À quoi ça delete o[e[0]];sert? Ne pouvons-nous pas simplement assigner?
Boyang
Il semble que seules les nouvelles affectations à des clés inexistantes ajouteront la clé à la fin. Si la suppression est commentée, les clés ne seront pas triées, du moins pas dans Chrome.
brunettdan
ça a du sens. Merci! Dans tous les cas, c'est une sorte de cause perdue car les clés d'objet js n'ont pas de séquence, selon les spécifications. Nous ne faisons qu'exploiter les détails des obj et des fonctions de journalisation
Boyang
Oui, j'utilise la carte lorsque l'ordre des clés est important: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
brunettdan
3
Object.keys(unordered).sort().reduce(
    (acc,curr) => ({...acc, [curr]:unordered[curr]})
    , {}
)
Marteau sauvage
la source
3

Il s'agit d'une solution légère à tout ce dont j'ai besoin pour le tri 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
la source
2

Utilisez ce code si vous avez des objets imbriqués ou si vous avez un obj de tableau imbriqué.

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
la source
5
L'auteur ne dit pas qu'il utilise jQuery, ni la question marquée jQuery. Ce serait bien si vous ajoutez une solution en pur javascript.
rusmus
Merci @Phani c'est exactement ce dont j'avais besoin
Will Sheppard
2

Solution:

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

Explication:

De nombreux runtimes JavaScript stockent les valeurs à l'intérieur d'un objet dans l'ordre dans lequel elles sont ajoutées.

Pour trier les propriétés d'un objet par leurs clés, vous pouvez utiliser la fonction Object.keys qui renverra un tableau de clés. Le tableau de clés peut ensuite être trié par la méthode Array.prototype.sort () qui trie les éléments d'un tableau en place (pas besoin de les affecter à une nouvelle variable).

Une fois les clés triées, vous pouvez commencer à les utiliser une par une pour accéder au contenu de l'ancien objet afin de remplir un nouvel objet (qui est maintenant trié).

Voici un exemple de la procédure (vous pouvez la tester dans vos navigateurs ciblés):

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

Remarque: Object.keys est une méthode ECMAScript 5.1 mais voici un polyfill pour les navigateurs plus anciens:

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
la source
2

J'ai transféré quelques énumérations Java vers des objets javascript.

Ces objets m'ont retourné des tableaux corrects. si les clés d'objet sont de type mixte (string, int, char), il y a un problème.

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
la source
2

Extrait simple et lisible, utilisant lodash.

Vous devez mettre la clé entre guillemets uniquement lorsque vous appelez sortBy. Il n'est pas nécessaire qu'il soit entre guillemets dans les données elles-mêmes.

_.sortBy(myObj, "key")

De plus, votre deuxième paramètre à mapper est incorrect. Cela devrait être une fonction, mais l'utilisation de la plumaison est plus facile.

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

Il y a un grand projet de @sindresorhus appelé sort-keys qui fonctionne très bien.

Vous pouvez vérifier son code source ici:

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

Ou vous pouvez l'utiliser avec npm:

$ npm install --save sort-keys

Voici également des exemples de code de son fichier Lisezmoi

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
la source
1

Réponse JavaScript pure pour trier un objet. C'est la seule réponse que je connaisse qui traitera les nombres négatifs. Cette fonction permet de trier des objets numériques.

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

La sortie sera un objet trié par ces nombres avec de nouvelles clés commençant à 0.

Cas
la source
1

Juste pour simplifier et rendre plus claire la réponse 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
la source
1

Je ne sais pas si cela répond à la question, mais c'est ce dont j'avais besoin.

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

Appelé comme:

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

La seule ligne:

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

la meilleure façon de le faire est

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

Vous pouvez d'abord convertir votre objet quasi-tableau en un vrai tableau, puis utiliser .reverse ():

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

L'emplacement vide à la fin est dû au fait que votre premier index est 1 au lieu de 0. Vous pouvez supprimer l'emplacement vide avec .length-- ou .pop ().

Alternativement, si vous souhaitez emprunter .reverse et l'appeler sur le même objet, il doit s'agir d'un objet de type tableau complet. Autrement dit, il a besoin d'une propriété de longueur:

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

Notez qu'il renverra le même objet objet de type tableau complet, donc ce ne sera pas un vrai tableau. Vous pouvez ensuite utiliser delete pour supprimer la propriété length.

Pedro JR
la source