Sortuj obiekt JavaScript według klucza


532

Muszę sortować obiekty JavaScript według klucza.

Stąd następujące:

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

Stanie się:

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


38
W 2011 r. (Kiedy opublikowano to pytanie) specyfikacja ECMAScript powiedziała, że ​​obiekty JavaScript nie mają właściwej kolejności - obserwowana kolejność zależy od implementacji i dlatego nie można na niej polegać. Okazuje się jednak, że wszystkie silniki JavaScript zaimplementowały mniej więcej taką samą semantykę, więc zostały one znormalizowane w ES6 . W rezultacie wiele poniższych odpowiedzi było poprawnych zgodnie ze specyfikacją, ale teraz są one nieprawidłowe.
Mathias Bynens,

w skrócie użyj sortowanego łańcucha znaków, gdy chcesz porównać lub zsumować
exebook

Biorąc pod uwagę, że obiekty są po prostu mapami lub dyktonami w zależności od języka, nie ma żadnego powodu, dla którego miałbyś to zrobić. KTÓRE SĄ POWIEDZONE Generalnie, kolejność ich wstrzykiwania do mapy jest w rzeczywistości kolejnością, w jakiej znajdują się podczas łączenia. Tak więc, jeśli utworzyłeś nową mapę i przypisałeś wartości na podstawie listy wstępnie wybranych kluczy, znajdziesz sobie uporządkowaną mapę opartą na kluczach
Fallenreaper

Zauważ, że od tego czasu Object.entriesi Object.fromEntriesdodawane do JS, można to osiągnąć za pomocą ładnie krótkiej Object.fromEntries(Object.entries(obj).sort())
linijki

Odpowiedzi:


471

Inne odpowiedzi na to pytanie są nieaktualne, nigdy nie pasowały do ​​rzeczywistości implementacyjnej i oficjalnie stały się niepoprawne po opublikowaniu specyfikacji ES6 / ES2015.


Zobacz sekcję dotyczącą kolejności iteracji właściwości w Exploring ES6 autorstwa Axela Rauschmayera :

Wszystkie metody iterujące po kluczach właściwości robią to w tej samej kolejności:

  1. Najpierw wszystkie indeksy macierzy, posortowane numerycznie.
  2. Następnie wszystkie klucze łańcuchowe (które nie są indeksami), w kolejności, w jakiej zostały utworzone.
  3. Następnie wszystkie symbole, w kolejności, w jakiej zostały utworzone.

Tak, tak, obiekty JavaScript w rzeczywistości uporządkowane, a kolejność ich kluczy / właściwości można zmienić.

Oto, w jaki sposób możesz posortować obiekt według jego kluczy / właściwości, alfabetycznie:

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

Użyj varzamiast constdla kompatybilności z silnikami ES5.


5
Naprawdę nie widzę różnicy w twoim kodzie i najważniejszej odpowiedzi tutaj oprócz użycia nieco innej techniki zapętlania. To, czy obiekty można uznać za „uporządkowane”, czy nie, wydaje się nieistotne. Odpowiedź na to pytanie jest nadal taka sama. Opublikowana specyfikacja jedynie potwierdza odpowiedzi tutaj.
Phil

6
Do wyjaśnienia, wyjaśniono, że kolejność wyliczania właściwości jest nadal nieokreślona: esdiscuss.org/topic/…
Felix Kling

6
@ Phil_1984_ Ta odpowiedź i najczęściej głosowane odpowiedzi są bardzo różne. Pytanie OP dotyczyło sposobu sortowania literału obiektu. Najczęściej głosowana odpowiedź mówi, że nie możesz, a następnie daje obejście, przechowując posortowane klucze w tablicy, a następnie iterując i drukując pary wartości kluczy z posortowanej tablicy. Ta odpowiedź twierdzi, że kolejność literałów obiektowych jest teraz sortowalna, a jego przykład przechowuje posortowane wartości kluczy z powrotem do literałów obiektowych, a następnie drukuje bezpośrednio posortowany obiekt. Na marginesie, byłoby miło, gdyby strona z linkami nadal istniała.
cchamberlain

6
Obie odpowiedzi po prostu używają funkcji Array.sort, aby najpierw posortować klucze. OP prosi o posortowanie „obiektu JavaScript” i używa jedynie JavaScript Object Notation (JSON) do opisania 2 obiektów. Te 2 obiekty są logicznie identyczne, co oznacza, że ​​sortowanie nie ma znaczenia. Myślę, że najlepsza odpowiedź wyjaśnia to znacznie lepiej. Mówienie „wszystkie inne odpowiedzi są teraz oficjalnie niepoprawne” jest dla mnie zbyt ekstremalne, szczególnie z zepsutym linkiem. Myślę, że problem polega na tym, że „ta nowa specyfikacja ES6” daje złudzenie, że obiekty Javascript mają uporządkowaną listę kluczy, co jest po prostu nieprawdą.
Phil

1
Dodaj, że to rozwiązanie nie jest obsługiwane przez wiele nowoczesnych przeglądarek (google „caniuse ES6”). Korzystanie z tych odpowiedzi grozi trudnymi do znalezienia błędami tylko w niektórych przeglądarkach (np. Safari, gdy Chrome działa prawidłowo).
Manuel Arwed Schmidt

244

Obiekty JavaScript 1 nie są uporządkowane. Nie ma sensu „sortować” ich. Jeśli chcesz wykonać iterację właściwości obiektu, możesz posortować klucze, a następnie pobrać powiązane wartości:

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


Alternatywne wdrożenie z wykorzystaniem Object.keysfanciness:

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 Nie być pedantycznym, ale nie ma czegoś takiego jak obiekt JSON .


2
@MarcelKorpel Istnieje coś takiego jak obiekt JSON. Sprawdź sekcję 8 oficjalnej JSON RFC: ietf.org/rfc/rfc4627.txt
Paul

8
@Paulpro należy zwrócić uwagę na dwie kwestie związane z RFC: po pierwsze, ma on teraz 7 lat i słownictwo zmienia się z czasem; po drugie: „Ta notatka zawiera informacje dla społeczności internetowej. Nie określa ona żadnego standardu internetowego”. To, czy dana sekwencja znaków reprezentuje literał obiektu JavaScript, czy tekst JSON, zależy od kontekstu / użycia. Termin „obiekt JSON” łączy się i czyni rozróżnienie dwuznacznym w szkodliwy sposób. Pozbądźmy się nieprecyzyjnej terminologii i, w miarę możliwości, używaj bardziej precyzyjnego terminu. Nie widzę powodu, by robić inaczej. Słowa się liczą.
Matt Ball

6
@MattBall IMO Obiekt JSON jest bardzo dokładnym terminem na ciąg znaków, podobnie {"a", 1}jak JSON Array jest dokładnym terminem na ciąg znaków [1]. Przydaje się możliwość komunikowania się poprzez wypowiadanie takich rzeczy, jak trzeci obiekt w mojej tablicy, gdy masz ciąg [{x: 1}, {y: 2}, {z: 3}], więc wolę „To nie jest obiekt JSON”, gdy komentuję dosłowność Javascript, niż „Nie ma takiego rzecz jako obiekt JSON ”, który po prostu spowoduje więcej zamieszania i trudności w komunikacji później, gdy OP faktycznie będzie współpracował z JSON.
Paul

3
@Paulpro Muszę się nie zgodzić. {"a", 1}jest literałem obiektu lub tekstem JSON (inaczej JSON string, jeśli naprawdę wolisz). To, co to jest, zależy od kontekstu, ten pierwszy, jeśli pojawia się dosłownie w kodzie źródłowym JavaScript, ten drugi, jeśli jest to ciąg, który należy przekazać do parsera JSON, aby go dalej użyć. Istnieją prawdziwe różnice między nimi, jeśli chodzi o dozwoloną składnię, prawidłowe użycie i serializację.
Matt Ball

4
Po sfinalizowaniu ES6 / ES2015 ta odpowiedź oficjalnie stała się niepoprawna. Zobacz moją odpowiedź, aby uzyskać więcej informacji.
Mathias Bynens

172

Wiele osób wspomniało, że „obiektów nie można sortować” , ale potem dają ci rozwiązanie, które działa. Paradoks, prawda?

Nikt nie wspomina, dlaczego te rozwiązania działają. Są, ponieważ w większości implementacji przeglądarki wartości w obiektach są przechowywane w kolejności, w jakiej zostały dodane. Dlatego jeśli tworzysz nowy obiekt z posortowanej listy kluczy, zwraca oczekiwany wynik.

I myślę, że moglibyśmy dodać jeszcze jedno rozwiązanie - funkcjonalny sposób ES5:

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

Powyższa wersja ES2015 (sformatowana jako „one-liner”):

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

Krótkie wyjaśnienie powyższych przykładów (zgodnie z pytaniami w komentarzach):

Object.keysdaje nam listę kluczy w podanym obiekcie ( objlub o), następnie sortujemy je za pomocą domyślnego algorytmu sortowania, następnie .reducesłuży do konwersji tej tablicy z powrotem na obiekt, ale tym razem z posortowanymi wszystkimi kluczami.


7
@Pointy To zachowanie zawsze było dostępne we wszystkich głównych przeglądarkach i zostało ustandaryzowane w ES6 / ES2015 . Powiedziałbym, że to dobra rada.
Mathias Bynens,

3
Jest to najprostszy i najbardziej zwięzły sposób wykonania zadania w EcmaScript v5. Trochę późno na imprezę, ale powinna być zaakceptowana odpowiedź.
Steven de Salas,

2
„Są, ponieważ w większości implementacji przeglądarki wartości w obiektach są przechowywane w kolejności, w jakiej zostały dodane” Jednak tylko dla właściwości nienumerycznych. Należy również pamiętać, że nadal nie ma gwarancji, w jakiej kolejności właściwości są iterowane (np. Via for...in).
Felix Kling

2
Miło z twojej strony, że wyjaśniłeś, dlaczego to działa, to dla mnie lekcja. Dzięki!
ola

5
Mój linijka narzekał na tę linijkę (zwrot zadania), ale ta działa dla mnie i jest mi łatwiej ją odczytać:Object.keys(dict).sort().reduce((r, k) => Object.assign(r, { [k]: dict[k] }), {});
aks.

68

Chłopaki jestem w szoku w przenośni! Oczywiście wszystkie odpowiedzi są nieco stare, ale nikt nawet nie wspomniał o stabilności sortowania! Więc proszę o cierpliwość, postaram się jak najlepiej odpowiedzieć na pytanie i przejść do szczegółów tutaj. Przepraszam, więc będzie dużo do przeczytania.

Ponieważ jest 2018, będę używać tylko ES6, wszystkie polifill są dostępne w dokumentach MDN, które podlinkuję w danej części.


Odpowiedz na pytanie:

Jeśli twoje klucze są tylko cyframi, możesz bezpiecznie użyć Object.keys()razem z, Array.prototype.reduce()aby zwrócić posortowany obiekt:

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

Jednak jeśli pracujesz z łańcuchami, bardzo polecam połączenie tego Array.prototype.sort()wszystkiego:

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

Jeśli ktoś zastanawia się, co robi redukcja:

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

W razie potrzeby znajduje się wyjaśnienie dla jednej wkładki:

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

Dlaczego sortowanie jest trochę skomplikowane:

W skrócie Object.keys()zwróci tablicę o takiej samej kolejności, jak w przypadku normalnej pętli:

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

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

Object.keys () zwraca tablicę, której elementy są łańcuchami odpowiadającymi wyliczalnym właściwościom znalezionym bezpośrednio na obiekcie. Kolejność właściwości jest taka sama, jak podana przez ręczne zapętlenie właściwości obiektu.

Sidenote - możesz używać również Object.keys()na tablicach, pamiętaj, że indeks zostanie zwrócony:

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

Ale nie jest to tak łatwe, jak pokazano w tych przykładach, obiekty świata rzeczywistego mogą zawierać liczby i znaki alfabetyczne, a nawet symbole (nie rób tego).

Oto przykład z nimi wszystkimi w jednym obiekcie:

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

Teraz, jeśli użyjemy Array.prototype.sort()tablicy powyżej zmiany danych wyjściowych:

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

Oto cytat z dokumentów:

Metoda sort () sortuje elementy tablicy na miejscu i zwraca tablicę. Sortowanie niekoniecznie jest stabilne. Domyślna kolejność sortowania jest zgodna z ciągami znaków kodu Unicode.

Nie można zagwarantować złożoności czasowej i przestrzennej tego rodzaju, ponieważ zależy ona od implementacji.

Musisz upewnić się, że jeden z nich zwróci dla Ciebie żądane wyjście. W rzeczywistych przykładach ludzie mają tendencję do pomieszania rzeczy, szczególnie jeśli używasz różnych danych wejściowych, takich jak interfejsy API i bazy danych.


Więc o co chodzi?

Cóż, są dwa artykuły, które każdy programista powinien zrozumieć:

Algorytm lokalny :

W informatyce algorytm lokalny jest algorytmem, który przekształca dane wejściowe bez żadnej struktury danych pomocniczych. Jednak niewielka ilość dodatkowej przestrzeni dyskowej jest dozwolona dla zmiennych pomocniczych. Dane wejściowe są zwykle nadpisywane przez dane wyjściowe podczas wykonywania algorytmu. Algorytm lokalny aktualizuje sekwencję wprowadzania tylko poprzez zamianę lub zamianę elementów. Algorytm, który nie jest na miejscu, jest czasem nazywany „nie na miejscu” lub „na miejscu”.

Więc w zasadzie nasza stara tablica zostanie nadpisana! Jest to ważne, jeśli chcesz zachować starą tablicę z innych powodów. Miej to na uwadze.

Algorytm sortowania

Stabilne algorytmy sortowania sortują identyczne elementy w tej samej kolejności, w jakiej pojawiają się na wejściu. Podczas sortowania niektórych rodzajów danych, tylko część danych jest sprawdzana podczas określania kolejności sortowania. Na przykład w przykładzie sortowania kart po prawej stronie, karty są sortowane według ich rangi, a ich kolor jest ignorowany. Pozwala to na wiele różnych poprawnie posortowanych wersji oryginalnej listy. Stabilne algorytmy sortowania wybierają jeden z nich, zgodnie z następującą zasadą: jeśli dwa elementy będą porównywane jako równe, podobnie jak dwie 5 kart, to ich względna kolejność zostanie zachowana, tak że jeśli jedna pojawi się przed drugą na wejściu, to również pojawiają się przed innymi w wyniku.

wprowadź opis zdjęcia tutaj

Przykład stabilnego sortowania na kartach do gry. Kiedy karty są sortowane według rangi przy użyciu stabilnego sortowania, dwie 5 muszą pozostać w tej samej kolejności na posortowanym wyjściu, w którym były pierwotnie. Kiedy są sortowane z niestabilnym sortowaniem, 5 mogą skończyć odwrotnie kolejność w posortowanym wyjściu.

To pokazuje, że sortowanie jest prawidłowe, ale się zmieniło. Tak więc w prawdziwym świecie, nawet jeśli sortowanie jest prawidłowe, musimy upewnić się, że otrzymamy to, czego oczekujemy! To bardzo ważne, należy o tym pamiętać. Więcej przykładów JavaScript można znaleźć w Array.prototype.sort () - docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort


3
Flippin rock, dziękuję za tę niesamowitą odpowiedź. Jeden z najlepszych, jakie widziałem na SO. Twoje zdrowie.
Gavin,

Gdybyś tylko mógł podać dziwaczną metodę do użycia na końcu. Świetna odpowiedź!
mmm

@Momomo problemem jest to, że w zależności od tego, czego oczekujesz od sortowania, nie ma właściwej metody. Jednakże można po prostu użyć tego kawałka kodu z moją odpowiedź: Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}).
Megajin

Czy tego rodzaju stabilność nie ma zastosowania do tego pytania: sortujemy według klucza obiektu, a klucz jest unikalny. (Aby rozszerzyć przykład karty: nigdy nie może być dwóch 5 w zestawie, nawet jeśli są one w różnych kolorach.)
Darren Cook

@DarrenCook dobre pytanie! Masz rację, nigdy nie będzie tego samego klucza w jednym obiekcie. Jednak stabilność jest bardziej złożona niż tylko wyjątkowość klucza. Przez większość czasu tablica znajduje się w sortowaniu obiektów. I wtedy wszystko może stać się niestabilne. Wyobraź sobie grę karcianą z 5 graczami. Każde rozdanie jest reprezentowane przez tablicę (aby zachować sortowanie poszczególnych rozdań), a karty jako obiekty. Jeśli twoja karta wygląda tak {5: 'hearts'}lub {5: 'spades'}zaczniesz sortować tablicę, stanie się ona potencjalnie niestabilna w grach takich jak remika. Nie mówiąc już o różnych językach.
Megajin

29

To działa dla mnie

/**
 * 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
To właściwie prawidłowa odpowiedź na pytanie. Aby zapoznać się z uproszczoną wersją używającą podkreślenia, patrz: jsfiddle.net/wPjaQ/1
radicand

6
@radicand Nie. Ta odpowiedź jest nieprawidłowa. Zwraca nowy obiekt, który również nie ma kolejności.
Paul

3
@radicand To też nie działa w praktyce. Nie ma czegoś takiego jak kolejność na kluczach obiektów, więc jak możesz powiedzieć, że w praktyce daje to obiekt w posortowanej kolejności? Naprawdę po prostu oddaje płytką kopię przedmiotu, który mi przekazujesz.
Paweł

9
To bardzo źle. Może się to na razie dziać, ale zepsuje inną przeglądarkę internetową lub inne ładowanie strony w tej samej przeglądarce. Przeglądarki mogą losowo losować klucze obiektów dla bezpieczeństwa lub gdy wypełnisz obiekt, umieści wartości w różnych segmentach pamięci w zależności od kluczy, co zwróci inną kolejność. Jeśli tak się stanie, to po prostu masz szczęście.
Yobert

11
Ma również niepotrzebne użycie jQuery.
RobG

25

Jest rok 2019 i mamy sposób na rozwiązanie tego w 2019 roku :)

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

2
Jak sortujemy zagnieżdżone obiekty według klucza?
a2441918

@ a2441918 W taki sam sposób, jak w przypadku funkcji sort (). Zobacz: developer.mozilla.org/de/docs/Web/JavaScript/Reference/… Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). Sortuj ((k, j ) => k - j))
user2912903

Dla użytkowników TypeScript nie jest to dla nas jeszcze dostępne, patrz: github.com/microsoft/TypeScript/issues/30933
tsujp

Fajny jednowarstwowy, ale jak sortować klucze bez rozróżniania wielkości liter?
theMaxx

1
@ theMaxx Użyj niestandardowej funkcji do sortowania, na przykład: `` Object.fromEntries (Object.entries ({b: 3, a: 8, c: 1}). sort (([key1, val1], [key2, val2]) => key1.toLowerCase (). localeCompare (key2.toLowerCase ()))) ``
Ben

22

tutaj jest 1 wkładka

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


Co do cholery jest ta szalona składnia? (o[k] = v, o). Dlaczego to w ogóle działa, gdzie mogę znaleźć dokumenty na ten temat? Oczywiście zwraca najbardziej prawy parametr, ale dlaczego?
ntaso

1
@ntaso tutaj
James

krótka funkcja powoduje, że najpierw jest o[k]równa, va następnie zwracao
Tahsin Turkoz

19

To stare pytanie, ale biorąc pod uwagę odpowiedź Mathiasa Bynensa, stworzyłem krótką wersję, aby posortować bieżący obiekt, bez większego obciążenia.

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

po wykonaniu kodu sam „nieuporządkowany” obiekt będzie posortowany alfabetycznie.


17

Przy użyciu lodash będzie to działać:

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

Tylko jedzenie do namysłu.


15

Załóżmy, że może to być przydatne w debuggerze VisualStudio, który pokazuje nieuporządkowane właściwości obiektu.

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

So Great Thanks a loooot
Mugiwara

Miły! Dziękuję za to zwięzłe rozwiązanie.
Con Antonakos,

9

Wersja podkreślenia :

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

Jeśli nie ufasz przeglądarce, że zachowuje porządek kluczy, zdecydowanie sugeruję, aby polegać na uporządkowanej tablicy sparowanych tablic klucz-wartość.

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

Lepiej:_.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,
});

Może lepiej jest dodać wyjaśnienie kodu.
aristotll

1
Pobiera klucze obiektu, więc jest to tablica ciągów, sortuję () je, a ponieważ jest to tablica ciągów (kluczy), zmniejszam je (za pomocą redukcji () tablicy js). Acc początkowo jest pustym obiektem {} (ostatni argument reduktora), a reduktor (wywołanie zwrotne) przypisuje do pustego obiektu wartości źródła obj z uporządkowaną sekwencją klawiszy.
user3286817,

8

Może nieco bardziej elegancka forma:

 /**
     * 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 i to samo ze składnią ES6 +:

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

nic nie sortuje. wciąż zwracasz przedmiot. nie możesz zagwarantować, że obiekty w twoim celu będą miały jakąkolwiek kolejność. musisz zwrócić tablicę. Jezu.
mmm

jedyne, co tu robisz, to zapewnienie zestawu w nieoptymalny sposób.
mmm

7

sortowanie rekurencyjne, dla zagnieżdżonych obiektów i tablic

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

Myślę, że potrzebujesz elsetam - może być prawdą dla obu Array.isArray(obj[key])i dlatypeof obj[key] === 'object'
jononomo

Gdy masz tablicę prymitywów, funkcja przekształca prymitywy (ciąg / liczba) w puste obiekty. Aby to złapać, dodałem na początku twojej funkcji function sortObjectKeys(obj){:: if(typeof obj != 'object'){ /* it is a primitive: number/string (in an array) */ return obj; }. Dla solidności I na samym początku dodałem również:if(obj == null || obj == undefined){ return obj; }
wydano


4

Oto czysta wersja oparta na lodash, która działa z zagnieżdżonymi obiektami

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

Byłoby jeszcze czystsze, gdyby lodash miał toObject()metodę ...


3

Wystarczy użyć lodash, aby rozpakować mapę i sortować.Pierwsza wartość pary i zip ponownie zwróci posortowany klucz.

Jeśli chcesz posortować wartość, zmień indeks par na 1 zamiast 0

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

wprowadź opis zdjęcia tutaj


Proszę użyć linku edycyjnego, aby wyjaśnić, jak działa ten kod, a nie tylko podać kod, ponieważ wyjaśnienie może pomóc przyszłym czytelnikom. Zobacz także Jak odpowiedzieć . źródło
Jed Fox

3

Sortuje klucze rekurencyjnie, zachowując odwołania.

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

Przykład:

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}

Niezły fragment! Jaki jest tego cel delete o[e[0]];? Czy nie możemy po prostu przypisać?
Boyang,

Wygląda na to, że tylko nowe przypisania do nieistniejących kluczy dołączą klucz na końcu. Jeśli usunięcie zostanie skomentowane, klucze nie zostaną posortowane, przynajmniej nie w Chrome.
brunettdan,

to ma sens. Dzięki! W każdym razie jest to rodzaj utraconej przyczyny, ponieważ klucze obiektowe js nie mają sekwencji, zgodnie ze specyfikacją. Po prostu wykorzystujemy szczegóły obiektu obj i funkcji logowania
Boyang

Tak, używam mapy, gdy kolejność kluczy jest ważna: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
brunettdan

3
Object.keys(unordered).sort().reduce(
    (acc,curr) => ({...acc, [curr]:unordered[curr]})
    , {}
)

3

Jest to lekkie rozwiązanie do wszystkiego, czego potrzebuję do sortowania 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

Użyj tego kodu, jeśli zagnieżdżałeś obiekty lub zagnieżdżałeś tablicę 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
Autor nie twierdzi, że używa jQuery, ani pytanie nie jest oznaczone jQuery. Byłoby miło, gdybyś dodał rozwiązanie w czystym javascript.
rusmus

Dzięki @Phani właśnie tego potrzebowałem
Will Sheppard,

2

Rozwiązanie:

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

Wyjaśnienie:

Wiele środowisk wykonawczych JavaScript zapisuje wartości wewnątrz obiektu w kolejności, w jakiej są dodawane.

Aby posortować właściwości obiektu według kluczy, możesz skorzystać z funkcji Object.keys, która zwróci tablicę kluczy. Tablicę kluczy można następnie posortować za pomocą Array.prototype.sort () metody , która sortuje elementy tablicy w miejscu (nie trzeba przypisywać ich do nowej zmiennej).

Po posortowaniu kluczy możesz zacząć używać ich jeden po drugim, aby uzyskać dostęp do zawartości starego obiektu w celu wypełnienia nowego obiektu (który jest teraz posortowany).

Poniżej znajduje się przykład procedury (możesz to przetestować w wybranych przeglądarkach):

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

Uwaga: Object.keys to metoda ECMAScript 5.1, ale tutaj jest wypełnianie wielu starszych przeglądarek:

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

Przekazałem niektóre wyliczenia Java do obiektów javascript.

Te obiekty zwróciły dla mnie prawidłowe tablice. jeśli klucze obiektów są typu mieszanego (string, int, char), istnieje problem.

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

Prosty i czytelny fragment kodu, korzystający z lodash.

Musisz wpisać klucz w cudzysłów tylko podczas wywoływania sortBy. Nie musi zawierać cudzysłowów w samych danych.

_.sortBy(myObj, "key")

Ponadto drugi parametr do mapowania jest nieprawidłowy. Powinna to być funkcja, ale łatwiejsze jest używanie skubania.

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

2

Jest świetny projekt @sindresorhus o nazwie sort-keys, który działa niesamowicie.

Możesz sprawdzić jego kod źródłowy tutaj:

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

Możesz też użyć go z npm:

$ npm install --save sort-keys

Oto także przykłady kodu z jego pliku 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

Czysta odpowiedź JavaScript do sortowania obiektu. To jedyna znana mi odpowiedź, która poradzi sobie z liczbami ujemnymi. Ta funkcja służy do sortowania obiektów numerycznych.

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

Wyjściem będzie obiekt posortowany według tych liczb z nowymi kluczami zaczynającymi się od 0.


1

Aby to uprościć i wyjaśnić odpowiedź 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]);
}


1

Nie jestem pewien, czy to odpowiada na pytanie, ale tego właśnie potrzebowałem.

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

Nazywany jako:

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

1

Jedna linia:

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

1

najlepszym sposobem na to jest

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

Możesz najpierw przekonwertować prawie podobny do tablicy obiekt na prawdziwą tablicę, a następnie użyć .reverse ():

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

Puste miejsce na końcu, jeśli powoduje, ponieważ twój pierwszy indeks to 1 zamiast 0. Możesz usunąć puste miejsce za pomocą .length-- lub .pop ().

Alternatywnie, jeśli chcesz pożyczyć .reverse i wywołać go na tym samym obiekcie, musi to być obiekt w pełni tablicowy. Oznacza to, że potrzebuje właściwości length:

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

Zauważ, że zwróci ten sam obiekt obiektowy w pełni tablicowy, więc nie będzie to prawdziwa tablica. Następnie możesz użyć delete, aby usunąć właściwość length.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.