Gibt es eine Möglichkeit, Schlüssel in JavaScript-Objekten zu sortieren / zu bestellen?

74

Zum Beispiel das Folgende

var data = {
    'States': ['NSW', 'VIC'],
    'Countries': ['GBR', 'AUS'],
    'Capitals': ['SYD', 'MEL']
}
for (var item in data) {
    console.log(item);
}

druckt

States
Countries
Capitals

Gibt es eine Möglichkeit, alphabetisch zu sortieren, damit es gedruckt wird?

Capitals
Countries
States
Hoa
quelle
Einen Blick wert: stackoverflow.com/questions/5525795/…
aymericbeaumet
1
Mögliches Duplikat von JavaScript-Objekt nach Schlüssel
sortieren
Ebenfalls einen Blick wert: sitepoint.com/sort-an-array-of-objects-in-javascript
Justice Bringer

Antworten:

129

Nicht innerhalb des Objekts selbst: Die Eigenschaftssammlung eines Objekts ist ungeordnet.

Sie können Object.keys()das Array verwenden , sortieren und anschließend iterieren.

Object.keys(data)
      .sort()
      .forEach(function(v, i) {
          console.log(v, data[v]);
       });

Patches (Implementierungen) für Browser, die ECMAScript 5th Edition nicht unterstützen:

Benutzer1106925
quelle
1
Es lohnt sich hinzuzufügen, dass .sort () durch .replace () ersetzt werden kann, wenn die Sortierreihenfolge umgekehrt werden soll. Außerdem akzeptieren sort () und reverse () Vergleichsfunktionen als Argumente, sodass Sie die Sortierung optimieren können. w3schools.com/jsref/jsref_sort.asp
Charles Jaimet
4
@ CharlesJaimet: Ich bin mir nicht sicher, was du damit meinst .replace(). Meinten Sie .reverse()? Das kann zwar verwendet werden, aber nur, wenn Sie die aktuelle Reihenfolge umkehren möchten. Wenn die sortierte Reihenfolge umgekehrt werden soll, muss sie zuerst sortiert werden. Die .sort()Methode akzeptiert zwar eine Funktion, aber .reverse()nicht.
Danke @squint. Zu schnell tippen, zu langsam denken. :)
Charles Jaimet
Dies löste mein Problem, aber ich würde gerne wissen, was das iArgument in der Funktion (v, i) darstellt
William Carron
2
@ WillCarron: Es sind die numerischen Indizes der aktuellen Iteration. Also , wenn es drei Tasten sind, die iwürden gegeben 0, 1, 2auf dem jeweiligen Aufruf des Rückrufs. Da ies in der Funktion nicht verwendet wird, kann es sicher entfernt werden, da JS niemals erfordert, dass Sie Parameter für alle oder einige der übergebenen Argumente angeben. Mithilfe der im Browser verfügbaren Protokollierungsfunktionen können Sie den Wert der Daten in Ihrer Anwendung überprüfen. console.log("The value of 'i' is:", i)
24

Hier ist eine schöne funktionale Lösung:

Grundsätzlich,

  1. Extrahieren Sie die Schlüssel in eine Liste mit Object.keys
  2. sort die Schlüssel
  3. Reduzieren Sie die Liste wieder auf ein Objekt, um das gewünschte Ergebnis zu erzielen

ES5-Lösung:

not_sorted = {b: false, a: true};

sorted = Object.keys(not_sorted)
    .sort()
    .reduce(function (acc, key) { 
        acc[key] = not_sorted[key];
        return acc;
    }, {});

console.log(sorted) //{a: true, b: false}

ES6-Lösung:

not_sorted = {b: false, a: true}

sorted = Object.keys(not_sorted)
    .sort()
    .reduce((acc, key) => ({
        ...acc, [key]: not_sorted[key]
    }), {})

console.log(sorted) //{a: true, b: false}
Mac
quelle
17

Ja da ist. Nicht innerhalb des ECMAScript-Standards, aber über Browser und Node.js hinweg unterstützt und anscheinend stabil. Siehe https://stackoverflow.com/a/23202095/645715 .

BEARBEITEN : Dies gibt ein Objekt zurück, in dem die Schlüssel angeordnet sind. Sie können verwenden Object.keys(...), um die bestellten Schlüssel vom Objekt abzurufen.

Warum sollten Sie sich um die Reihenfolge der Objektschlüssel kümmern? Der Unterschied kann in einigen Anwendungen von Bedeutung sein, z. B. beim Parsen von XML mit xml2js, das XML als verschachtelte Objekte darstellt und XML-Tags als Hash-Schlüssel verwendet.

Es gibt ein paar Anmerkungen:

  • Schlüssel, die wie Ganzzahlen aussehen, werden zuerst und in numerischer Reihenfolge angezeigt.
  • Tasten, die wie Zeichenfolgen aussehen, werden als Nächstes und in der Einfügereihenfolge angezeigt.
  • Diese Bestellung wird von gemeldet Object.keys(obj)
  • Die von gemeldete Reihenfolge for (var key in obj) {...}kann in Safari, Firefox abweichen

Die Funktion gibt ein Objekt mit sortierten Schlüsseln zurück, die in alphabetischer Reihenfolge eingefügt sind:

function orderKeys(obj, expected) {

  var keys = Object.keys(obj).sort(function keyOrder(k1, k2) {
      if (k1 < k2) return -1;
      else if (k1 > k2) return +1;
      else return 0;
  });

  var i, after = {};
  for (i = 0; i < keys.length; i++) {
    after[keys[i]] = obj[keys[i]];
    delete obj[keys[i]];
  }

  for (i = 0; i < keys.length; i++) {
    obj[keys[i]] = after[keys[i]];
  }
  return obj;
}

Hier ist ein kurzer Test:

var example = { 
      "3": "charlie",
      "p:style": "c",
      "berries": "e",
      "p:nvSpPr": "a",
      "p:txBody": "d",
      "apples": "e",
      "5": "eagle",
      "p:spPr": "b"
    }

var obj = orderKeys(example);

dies kehrt zurück

{ '3': 'charlie',
  '5': 'eagle',
  apples: 'e',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:spPr': 'b',
  'p:style': 'c',
  'p:txBody': 'd' }

Sie können dann die bestellten Schlüssel erhalten als:

Object.keys(obj) 

Welches kehrt zurück

["3", "5", "apples", "berries", "p:nvSpPr", "p:spPr", "p:style", "p:txBody"]
Prototyp
quelle
ja Dankeschön. funktioniert hervorragend bei so etwas: {2018-04-02 05:46:51: "0.0000003900", 2018-04-02 04:46:48: "0.0000004000", 2018-04-03 01:00:35: " 0.0000004000 ", 2018-04-02 06:46:55:" 0.0000003900 ", 2018-04-02 02:46:34:" 0.0000004000 ",…} 2018-04-02 01:46:25:" 0.0000003900 "2018 -04-02 02:46:34: "0.0000004000" 2018-04-02 03:46:42: "0.0000003900" 2018-04-02 04:46:48: "0.0000004000" 2018-04-02 05:46: 51: "0.0000003900" 2018-04-02 06:46:55: "0.0000003900" 2018-04-03 00:00:32: "0.0000003900" 2018-04-03 01:00:35: "0.0000004000" proto : Object
Ray Koren
Vielen Dank dafür. Was macht expectedhier? Es beschwert sich nicht, wenn es nicht geliefert wird.
Vael Victus
1
@VaelVictus Großartiger Fang, es wurde aus einem Unit-Test kopiert und ist jetzt nicht mehr erforderlich.
Prototyp
2

Hier ist ein Einzeiler, um die Schlüssel eines Objekts mit lodash zu sortieren

_.chain(obj).toPairs().sortBy(0).fromPairs().value()

Mit Ihren Beispieldaten:

var data = {
    'States': ['NSW', 'VIC'],
    'Countries': ['GBR', 'AUS'],
    'Capitals': ['SYD', 'MEL']
}
data = _.chain(data)
  .toPairs() // turn the object into an array of [key, value] pairs
  .sortBy(0) // sort these pairs by index [0] which is [key]
  .fromPairs() // convert array of pairs back into an object {key: value}
  .value() // return value
/*
{
  Capitals: [ 'SYD', 'MEL' ],
  Countries: [ 'GBR', 'AUS' ],
  States: [ 'NSW', 'VIC' ]
}
*/

Jinksi
quelle
2

Ich würde dies als Kommentar zum Beitrag von @prototype hinzufügen , aber mein Repräsentant ist nicht hoch genug.

Wenn jemand eine Version orderKeysdieses @prototype benötigt, die geschrieben wurde , entspricht dies eslint-config-airbnb:

/**
 * Returns and modifies the input object so that its keys are returned in sorted
 * order when `Object.keys(obj)` is invoked
 *
 * @param {object} obj The object to have its keys sorted
 *
 * @returns {object} The inputted object with its keys in sorted order
 */
const orderKeys = (obj) => {
  // Complying with `no-param-reassign`, and JavaScript seems to assign by reference here
  const newObj = obj;
  // Default `.sort()` chained method seems to work for me
  const keys = Object.keys(newObj).sort();

  const after = {};
  // Add keys to `after` in sorted order of `obj`'s keys
  keys.forEach((key) => {
    after[key] = newObj[key];
    delete newObj[key];
  });

  // Add keys back to `obj` in sorted order
  keys.forEach((key) => {
    newObj[key] = after[key];
  });

  return newObj;
};

Verwenden der Tests von @prototype :

const example = { 
  3: 'charlie',
  'p:style': 'c',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:txBody': 'd',
  apples: 'e',
  5: 'eagle',
  p:spPr: 'b'
}

const obj = orderKeys(example);

console.log(obj);

console.log(Object.keys(obj));

Gibt Folgendes aus:

Babel Compiler v6.4.4
Copyright (c) 2014-2015 Sebastian McKenzie

{ 3: 'charlie',
  5: 'eagle',
  apples: 'e',
  berries: 'e',
  'p:nvSpPr': 'a',
  'p:spPr': 'b',
  'p:style': 'c',
  'p:txBody': 'd' }
[ '3',
  '5',
  'apples',
  'berries',
  'p:nvSpPr',
  'p:spPr',
  'p:style',
  'p:txBody' ]

Was auch immer es wert ist, ich brauchte dies in meiner React-App, damit ich die Optionen eines Dropdowns sortieren konnte, das auf einem stateObjekt basierte , das nach einer Antwort von meiner API zugewiesen wurde.

Anfangs habe ich es getan

return (
  // ...
  <Select
    options={Object.keys(obj).sort()}
    // ...
  />
  // ...
);

Es wurde jedoch erkannt, dass die .sort()Methode bei jedem erneuten Rendern aufgerufen wird, sodass die Implementierung von @prototype erforderlich ist orderKeys.

https://stackoverflow.com/users/645715/prototype

CorreyL
quelle
1

Sie können es auch auf diese Weise sortieren.

const data = {
  States: ['NSW', 'VIC'],
  Countries: ['GBR', 'AUS'],
  Capitals: ['SYD', 'MEL']
}

const sortedObject = Object.fromEntries(Object.entries(data).sort())

Ich kann nicht im Detail erklären, warum es funktioniert, aber anscheinend funktioniert es einwandfrei :) Versuchen Sie es selbst, wenn Sie mir nicht glauben: D.

Beachten Sie, dass Ihr Browser oder die Node.js-Version dies unterstützen sollte Object.fromEntries

Überprüfen Sie die Browserkompatibilität unten auf dieser Seite

Für Node funktioniert es für Versionen ab 12. Für Deno aus der v1.

Andrii Los
quelle
-3

Wenn die Konvertierung in ein Array nicht zu Ihrer Vorlage passt und Sie die Schlüssel Ihres Objekts kennen, können Sie auch Folgendes tun:

Definieren Sie in Ihrem Controller ein Array mit den Schlüsseln in der richtigen Reihenfolge:

this.displayOrder = [
    'firstKey',
    'secondKey',
    'thirdKey'
];

Wiederholen Sie in Ihrer Vorlage die Tasten Ihrer displayOrder und verwenden Sie dann ng-init, um auf Ihr Objekt zurückzugreifen.

<div ng-repeat="key in ctrl.displayOrder" ng-init="entry = ctrl.object[key]">
     {{ entry.detail }}
</div>
Stanley85
quelle