webentwicklung-frage-antwort-db.com.de

Wie kann ich ein assoziatives Array nach seinen Werten in Javascript sortieren?

Ich habe das assoziative Array:

array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;

Was ist der eleganteste Weg, um (absteigend) nach seinen Werten zu sortieren, wobei das Ergebnis ein Array mit den jeweiligen Indizes in dieser Reihenfolge sein würde:

sub2, sub3, sub1, sub4, sub0?
77
John Smith

Javascript hat keine "assoziativen Arrays", wie Sie sie denken. Stattdessen haben Sie einfach die Möglichkeit, Objekteigenschaften mithilfe von arrayartiger Syntax (wie in Ihrem Beispiel) festzulegen, und können auch die Eigenschaften eines Objekts durchlaufen.

Das Ergebnis davon ist, dass es keine Garantie für die order gibt, in der Sie die Eigenschaften durchlaufen. Stattdessen müssen Sie Ihre Objekteigenschaften in ein "wahres" Array (das die Reihenfolge garantiert) konvertieren. Hier ist ein Code-Snippet, mit dem Sie ein Objekt in ein Array von Zwei-Tupeln (Zwei-Element-Arrays) konvertieren, es wie beschrieben sortieren und dann darüber iterieren:

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
}

Sie finden es vielleicht natürlicher, dies in eine Funktion zu packen, die einen Rückruf erfordert:

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>

110
Ben Blank

Anstatt Sie über die Semantik eines "assoziativen Arrays" zu korrigieren, denke ich, dass Sie Folgendes wünschen:

function getSortedKeys(obj) {
    var keys = []; for(var key in obj) keys.Push(key);
    return keys.sort(function(a,b){return obj[b]-obj[a]});
}

Sie legen ein Objekt ab (wie Ihres) und erhalten ein Array mit den Schlüsseln - eh Eigenschaften - zurück, sortiert nach dem (numerischen) Wert des, eh, Werten des, eh, Objekts.

Dies funktioniert nur, wenn Ihre Werte numerisch sind. Tweek die kleine function(a,b) dort, um den Sortiermechanismus in aufsteigender Reihenfolge zu ändern, oder für string-Werte (zum Beispiel). Links als Übung für den Leser.

EDIT: Die Leute stimmen immer wieder mit dieser Antwort überein, aber sie ist wirklich alt. Bitte Überdenken Sie, warum Sie nicht nur Object.keys () heutzutage verwenden: var keys = Object.keys(obj);

74
commonpike

Weitere Diskussionen und andere Lösungen unter Wie sortiere ich ein (assoziatives) Array nach Wert? mit der besten Lösung (für meinen Fall) von saml (unten zitiert).

Arrays können nur numerische Indizes haben. Sie müssen dies entweder als Objekt oder als Array von Objekten umschreiben.

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

Wenn Ihnen die status.Push-Methode gefällt, können Sie sie wie folgt sortieren:

status.sort(function(a,b) {
    return a.val - b.val;
});
15
PopeJohnPaulII

In JavaScript gibt es eigentlich kein "assoziatives Array". Was Sie dort haben, ist nur ein einfaches altes Objekt. Sie funktionieren irgendwie wie assoziative Arrays, und die Schlüssel sind verfügbar, aber es gibt keine Semantik um die Reihenfolge der Schlüssel.

Sie können Ihr Objekt in ein Array von Objekten (Schlüssel/Wert-Paare) umwandeln und diese sortieren:

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

Dann würden Sie das mit einer Vergleicherfunktion aufrufen.

5
Pointy

Keine unnötigen Komplikationen erforderlich ...

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

Hier ist eine Variation der Antwort von ben blank, wenn Sie keine Tupel mögen. 

Dies erspart Ihnen einige Zeichen.

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.
}
4
donquixote

ich benutze $ .each von Jquery, aber Sie können es mit einer for-Schleife machen.

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

So können Sie jetzt tun

    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);
1
demosthenes

Der beste Ansatz für den speziellen Fall ist meiner Meinung nach derjenige, der commonpike vorgeschlagen wird. Eine kleine Verbesserung, die ich vorschlagen kann, funktioniert in modernen Browsern:

// aao is the "associative array" you need to "sort"
Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});

Dies könnte leicht zutreffen und im konkreten Fall hier gut funktionieren, so dass Sie Folgendes tun können:

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

Außerdem habe ich hier eine "generische" Funktion, mit der Sie auch in weiteren Situationen sortieren können. Diese Verbesserung mischt die Verbesserung, die ich gerade vorgeschlagen habe, mit den Ansätzen der Antworten von Ben Blank (auch Sortieren Zeichenfolgewerte) und PopeJohnPaulII (Sortieren nach bestimmten Objektfeldern/Eigenschaften) und lässt Sie entscheiden, ob Sie eine aufsteigende oder absteigende Reihenfolge wünschen. Hier ist es:

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

Sie können die Funktionen testen, indem Sie etwa folgenden Code verwenden:

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

Wie ich schon sagte, können Sie sortierte Schlüssel durchlaufen, wenn Sie Dinge erledigen müssen

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

Zu guter Letzt einige nützliche Verweise auf Object.keys und Array.sort

0
danicotra

Nur so ist es da draußen und jemand sucht nach Tuple-basierten Sorten. Dadurch wird das erste Element des Objekts im Array und das zweite Element usw. verglichen. Im folgenden Beispiel wird es zuerst mit "a", dann mit "b" usw. verglichen.

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

OUPUTS

 [ { 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 } ]
0
Shayan C