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' }
vdh_ant
źródło
3
możliwy duplikat sortowania obiektu JSON w JavaScript
abraham,
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.

Mathias Bynens
źródło
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 .

Matt Ball
źródło
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.

kryptonim-
źródło
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

Megajin
źródło
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;
};
Ashit Vora
źródło
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())
Ben
źródło
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), {} ));

Sravan Ganji
źródł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.

Sergio Moura
źródło
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.

Brian M. Hunt
źródło
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})
Serg
źródło
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]})
Flavien Volken
źródło
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,
});
użytkownik3286817
źródło
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;
  }, {});
};
Dmitry Sheiko
źródło
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!'
            }
        },
    ]
});
użytkownik3286817
źródło
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

Jak już wspomniano, obiekty są nieuporządkowane.

Jednak...

Ten idiom może ci się przydać:

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

var kv = [];

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

kv.sort()

Następnie możesz iterować przez kv i robić, co chcesz.

> kv.sort()
[ [ 'a', 'dsfdsfsdf' ],
  [ 'b', 'asdsad' ],
  [ 'c', 'masdas' ] ]
Steven Keith
źródło
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ę ...

BlueRaja - Danny Pflughoeft
źródło
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

Narayanaperumal Gurusamy
źródło
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}
brunettdan
źródło
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]})
    , {}
)
Wildhammer
źródło
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;
    }, {});
}
Alan Hape
źródło
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;
};
Phani Reddy
źródło
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;
  };
}
Benny Neugebauer
źródło
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"]
Sherali Turdiyev
źródło
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");
JLavoie
źródło
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}
fernandopasik
źródło
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.

Walizka
źródło
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]);
}

João Pimentel Ferreira
źródło
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) { ... } ) 
mmm
źródło
1

Jedna linia:

Object.entries(unordered)
  .sort(([keyA], [keyB]) => keyA > keyB)
  .reduce((obj, [key,value]) => Object.assign(obj, {[key]: value}), {})
metakungfu
źródło
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.

Pedro JR
źródło