Mam tablicę asocjacyjną:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
Jaki jest najbardziej elegancki sposób sortowania (malejąco) według wartości, gdzie wynikiem byłaby tablica z odpowiednimi indeksami w następującej kolejności:
sub2, sub3, sub1, sub4, sub0
javascript
arrays
sorting
associative
John Smith
źródło
źródło
Odpowiedzi:
JavaScript nie ma „tablic asocjacyjnych” w sposób, w jaki o nich myślisz. Zamiast tego masz po prostu możliwość ustawiania właściwości obiektu przy użyciu składni podobnej do tablicy (jak w twoim przykładzie), a także możliwość iteracji po właściwościach obiektu.
W rezultacie nie ma gwarancji kolejności, w jakiej iterujesz po właściwościach, więc nie ma dla nich żadnego rodzaju. Zamiast tego będziesz musiał przekonwertować właściwości obiektu na „prawdziwą” tablicę (która gwarantuje porządek). Oto fragment kodu służący do konwersji obiektu na tablicę dwóch krotek (tablice dwuelementowe), sortowania go zgodnie z opisem, a następnie iterowania po nim:
var tuples = []; for (var key in obj) tuples.push([key, obj[key]]); tuples.sort(function(a, b) { a = a[1]; b = b[1]; return a < b ? -1 : (a > b ? 1 : 0); }); for (var i = 0; i < tuples.length; i++) { var key = tuples[i][0]; var value = tuples[i][1]; // do something with key and value }
Może się okazać, że bardziej naturalne będzie zawinięcie tego w funkcję, która pobiera wywołanie zwrotne:
function bySortedValue(obj, callback, context) { var tuples = []; for (var key in obj) tuples.push([key, obj[key]]); tuples.sort(function(a, b) { return a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0 }); var length = tuples.length; while (length--) callback.call(context, tuples[length][0], tuples[length][1]); } bySortedValue({ foo: 1, bar: 7, baz: 3 }, function(key, value) { document.getElementById('res').innerHTML += `${key}: ${value}<br>` });
<p id='res'>Result:<br/><br/><p>
źródło
Zamiast poprawiać semantykę `` tablicy asocjacyjnej '', myślę, że tego chcesz:
function getSortedKeys(obj) { var keys = keys = Object.keys(obj); return keys.sort(function(a,b){return obj[b]-obj[a]}); }
w przypadku naprawdę starych przeglądarek użyj tego:
function getSortedKeys(obj) { var keys = []; for(var key in obj) keys.push(key); return keys.sort(function(a,b){return obj[b]-obj[a]}); }
Zrzucasz obiekt (taki jak twój) i otrzymujesz tablicę kluczy - eh właściwości - z powrotem, posortowanych malejąco według (numerycznej) wartości, eh, wartości, eh, obiektu.
Działa to tylko wtedy, gdy wartości są liczbowe. Popraw trochę
function(a,b)
tam, aby zmienić mechanizm sortowania, aby działał rosnąco lub pracował dlastring
wartości (na przykład). Pozostawione jako ćwiczenie dla czytelnika.źródło
Ciągła dyskusja i inne rozwiązania omówione w temacie Jak sortować (asocjacyjną) tablicę według wartości? najlepszym rozwiązaniem (w moim przypadku) jest saml (cytowane poniżej).
Tablice mogą mieć tylko indeksy numeryczne. Musiałbyś przepisać to jako obiekt lub tablicę obiektów.
var status = new Array(); status.push({name: 'BOB', val: 10}); status.push({name: 'TOM', val: 3}); status.push({name: 'ROB', val: 22}); status.push({name: 'JON', val: 7});
Jeśli podoba Ci się ta
status.push
metoda, możesz ją posortować za pomocą:status.sort(function(a,b) { return a.val - b.val; });
źródło
sort()
traktuje je inaczej. Wkurzało mnie przez godzinę, aż znalazłem ten stackoverflow.com/questions/6712034/… Przykład;a.name.toLowerCase() > b.name.toLowerCase()
Naprawdę nie ma czegoś takiego jak „tablica asocjacyjna” w JavaScript. To, co tam masz, to zwykły stary przedmiot. Działają one oczywiście podobnie jak tablice asocjacyjne, a klucze są dostępne, ale nie ma semantyki wokół kolejności kluczy.
Możesz przekształcić swój obiekt w tablicę obiektów (pary klucz / wartość) i posortować to:
function sortObj(object, sortFunc) { var rv = []; for (var k in object) { if (object.hasOwnProperty(k)) rv.push({key: k, value: object[k]}); } rv.sort(function(o1, o2) { return sortFunc(o1.key, o2.key); }); return rv; }
Następnie nazwałbyś to funkcją komparatora.
źródło
Oto odmiana odpowiedzi Bena Blanka, jeśli nie lubisz krotek.
Oszczędza to kilka znaków.
var keys = []; for (var key in sortme) { keys.push(key); } keys.sort(function(k0, k1) { var a = sortme[k0]; var b = sortme[k1]; return a < b ? -1 : (a > b ? 1 : 0); }); for (var i = 0; i < keys.length; ++i) { var key = keys[i]; var value = sortme[key]; // Do something with key and value. }
źródło
Bez zbędnych komplikacji ...
function sortMapByValue(map) { var tupleArray = []; for (var key in map) tupleArray.push([key, map[key]]); tupleArray.sort(function (a, b) { return a[1] - b[1] }); return tupleArray; }
źródło
var stuff = {"a":1 , "b":3 , "c":0 } sortMapByValue(stuff) [Array[2], Array[2], Array[2]]
używam $ .each z jquery, ale możesz to zrobić za pomocą pętli for, poprawa jest następująca:
//.ArraySort(array) /* Sort an array */ ArraySort = function(array, sortFunc){ var tmp = []; var aSorted=[]; var oSorted={}; for (var k in array) { if (array.hasOwnProperty(k)) tmp.push({key: k, value: array[k]}); } tmp.sort(function(o1, o2) { return sortFunc(o1.value, o2.value); }); if(Object.prototype.toString.call(array) === '[object Array]'){ $.each(tmp, function(index, value){ aSorted.push(value.value); }); return aSorted; } if(Object.prototype.toString.call(array) === '[object Object]'){ $.each(tmp, function(index, value){ oSorted[value.key]=value.value; }); return oSorted; } };
Więc teraz możesz to zrobić
console.log("ArraySort"); var arr1 = [4,3,6,1,2,8,5,9,9]; var arr2 = {'a':4, 'b':3, 'c':6, 'd':1, 'e':2, 'f':8, 'g':5, 'h':9}; var arr3 = {a: 'green', b: 'brown', c: 'blue', d: 'red'}; var result1 = ArraySort(arr1, function(a,b){return a-b}); var result2 = ArraySort(arr2, function(a,b){return a-b}); var result3 = ArraySort(arr3, function(a,b){return a>b}); console.log(result1); console.log(result2); console.log(result3);
źródło
Najlepszym rozwiązaniem dla przypadku szczególnego tutaj, moim zdaniem, jest jednym commonpike sugerowane. Małe ulepszenie, które proponuję, które działa w nowoczesnych przeglądarkach to:
// aao is the "associative array" you need to "sort" Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
Można to łatwo zastosować i świetnie działać w konkretnym przypadku tutaj, więc możesz:
let aoo={}; aao["sub2"]=1; aao["sub0"]=-1; aao["sub1"]=0; aao["sub3"]=1; aao["sub4"]=0; let sk=Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]}); // now you can loop using the sorted keys in `sk` to do stuffs for (let i=sk.length-1;i>=0;--i){ // do something with sk[i] or aoo[sk[i]] }
Poza tym, podaję tutaj bardziej "ogólną" funkcję, której możesz użyć do sortowania nawet w szerszym zakresie sytuacji i która łączy poprawę, którą właśnie zasugerowałem, z podejściem do odpowiedzi Bena Blanka (sortowanie również wartości ciągów) i PopeJohnPaulII ( sortowanie według określonego pola / właściwości obiektu) i pozwala zdecydować, czy chcesz uzyskać kolejność rosnącą, czy podrzędną, oto ona:
// aao := is the "associative array" you need to "sort" // comp := is the "field" you want to compare or "" if you have no "fields" and simply need to compare values // intVal := must be false if you need comparing non-integer values // desc := set to true will sort keys in descendant order (default sort order is ascendant) function sortedKeys(aao,comp="",intVal=false,desc=false){ let keys=Object.keys(aao); if (comp!="") { if (intVal) { if (desc) return keys.sort(function(a,b){return aao[b][comp]-aao[a][comp]}); else return keys.sort(function(a,b){return aao[a][comp]-aao[a][comp]}); } else { if (desc) return keys.sort(function(a,b){return aao[b][comp]<aao[a][comp]?1:aao[b][comp]>aao[a][comp]?-1:0}); else return keys.sort(function(a,b){return aao[a][comp]<aao[b][comp]?1:aao[a][comp]>aao[b][comp]?-1:0}); } } else { if (intVal) { if (desc) return keys.sort(function(a,b){return aao[b]-aao[a]}); else return keys.sort(function(a,b){return aao[a]-aao[b]}); } else { if (desc) return keys.sort(function(a,b){return aao[b]<aao[a]?1:aao[b]>aao[a]?-1:0}); else return keys.sort(function(a,b){return aao[a]<aao[b]?1:aao[a]>aao[b]?-1:0}); } } }
Możesz przetestować funkcje, próbując czegoś takiego jak poniższy kod:
let items={}; items['Edward']=21; items['Sharpe']=37; items['And']=45; items['The']=-12; items['Magnetic']=13; items['Zeros']=37; //equivalent to: //let items={"Edward": 21, "Sharpe": 37, "And": 45, "The": -12, ...}; console.log("1: "+sortedKeys(items)); console.log("2: "+sortedKeys(items,"",false,true)); console.log("3: "+sortedKeys(items,"",true,false)); console.log("4: "+sortedKeys(items,"",true,true)); /* OUTPUT 1: And,Sharpe,Zeros,Edward,Magnetic,The 2: The,Magnetic,Edward,Sharpe,Zeros,And 3: The,Magnetic,Edward,Sharpe,Zeros,And 4: And,Sharpe,Zeros,Edward,Magnetic,The */ items={}; items['k1']={name:'Edward',value:21}; items['k2']={name:'Sharpe',value:37}; items['k3']={name:'And',value:45}; items['k4']={name:'The',value:-12}; items['k5']={name:'Magnetic',value:13}; items['k6']={name:'Zeros',value:37}; console.log("1: "+sortedKeys(items,"name")); console.log("2: "+sortedKeys(items,"name",false,true)); /* OUTPUT 1: k6,k4,k2,k5,k1,k3 2: k3,k1,k5,k2,k4,k6 */
Jak już powiedziałem, możesz zapętlić posortowane klucze, jeśli potrzebujesz coś zrobić
let sk=sortedKeys(aoo); // now you can loop using the sorted keys in `sk` to do stuffs for (let i=sk.length-1;i>=0;--i){ // do something with sk[i] or aoo[sk[i]] }
Na koniec kilka przydatnych odniesień do Object.keys i Array.sort
źródło
Tak więc jest tam i ktoś szuka typów opartych na krotkach. Spowoduje to porównanie pierwszego elementu obiektu w tablicy, z drugim elementem i tak dalej. tj. w poniższym przykładzie porównuje najpierw „a”, potem „b” i tak dalej.
let arr = [ {a:1, b:2, c:3}, {a:3, b:5, c:1}, {a:2, b:3, c:9}, {a:2, b:5, c:9}, {a:2, b:3, c:10} ] function getSortedScore(obj) { var keys = []; for(var key in obj[0]) keys.push(key); return obj.sort(function(a,b){ for (var i in keys) { let k = keys[i]; if (a[k]-b[k] > 0) return -1; else if (a[k]-b[k] < 0) return 1; else continue; }; }); } console.log(getSortedScore(arr))
WYJŚCIA
[ { a: 3, b: 5, c: 1 }, { a: 2, b: 5, c: 9 }, { a: 2, b: 3, c: 10 }, { a: 2, b: 3, c: 9 }, { a: 1, b: 2, c: 3 } ]
źródło
Odpowiedź @ commonpike jest „właściwa”, ale gdy komentuje ...
Tak ..
Object.keys()
jest DUŻO lepiej .Ale co jest jeszcze lepsze ? Duh, już jest
coffeescript
!sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b] sortedKeys 'a' : 1 'b' : 3 'c' : 4 'd' : -1
źródło