Durchlaufen Sie ein assoziatives Javascript-Array in sortierter Reihenfolge

109

Angenommen, ich habe ein assoziatives Javascript-Array (auch bekannt als Hash, auch bekannt als Dictionary):

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

Wie kann ich die Schlüssel in sortierter Reihenfolge durchlaufen? Wenn es hilft, die Dinge zu vereinfachen, brauche ich nicht einmal die Werte (sie sind alle nur die Nummer 1).

Mike
quelle
11
Warum verwenden Sie das neue Array () -Konstrukt und verwenden es dann wie ein Objekt?
Luke Schafer
@ Luke .. Ich habe das zuerst auch gemacht, aus einem PHP-Hintergrund. Ich habe jetzt aber gelernt :)
Alex
20
@ Luke: Weil ich unerfahren bin, scheint es. Können Sie in einer Antwort den richtigen Weg posten?
Mike
4
Sie können einfach ein beliebiges Objekt erstellen. In Javascript gibt es keinen Unterschied zwischen einem Wörterbuch / "benannten Array" und einem regulären Objekt. Sie können daher mit ab auf ein ['b'] zugreifen und umgekehrt. Der kürzeste Weg, um ein Objekt zu erstellen, ist a = {};.
Lodewijk

Antworten:

124

Sie können sie nicht direkt durchlaufen, aber Sie können alle Schlüssel finden und sie dann einfach sortieren.

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;    

function keys(obj)
{
    var keys = [];

    for(var key in obj)
    {
        if(obj.hasOwnProperty(key))
        {
            keys.push(key);
        }
    }

    return keys;
}

keys(a).sort(); // ["a", "b", "z"]

Es ist jedoch nicht erforderlich, die Variable 'a' zu einem Array zu machen. Sie verwenden es wirklich nur als Objekt und sollten es folgendermaßen erstellen:

var a = {};
a["key"] = "value";
Matthew
quelle
28
Sie sollten immer in der forSchleife überprüfen , ob obj.hasOwnProperty(key).
viam0Zah
3
@Lalit - Wenn Sie sich auf Toroks Kommentar beziehen, liegt das daran, dass Sie nichts haben, was den Prototyp des Objekts stört, auf das Sie sich nicht verlassen können.
Luke Schafer
1
+1 nach Torok. Es wäre schön, wenn die Antwort hasOwnProperty () enthalten würde.
Jon Onstott
136

Sie können die integrierte Methode Object.keys verwenden:

var sorted_keys = Object.keys(a).sort()

(Hinweis: Dies funktioniert nicht in sehr alten Browsern, die EcmaScript5 nicht unterstützen, insbesondere IE6, 7 und 8. Detaillierte aktuelle Statistiken finden Sie in dieser Tabelle. )

Molnarg
quelle
@ michael667 Wahrscheinlich, weil IE 7 und 8 immer noch weit verbreitet sind (leider danke MS)
Alexander Reifinger
1
IE7 liegt zum Glück bei 0,5% und IE8 bei 8%.
Molnarg
3
if (!Object.keys) { Object.keys = function (obj) { var op, result = []; for (op in obj) { if (obj.hasOwnProperty(op) { result.push(op) } } return result }
Jordan Reiter
Ich liebe diesen, danke. Hier ist mein Code, der dies nutzt: $ (Object.keys (Liste)). map (Funktion (i, e) {return n + '=' + Liste [n];}). get (). join ('&'); // Concat für URL Querystring
Elaine
1
Update 2016: Dies sollte wahrscheinlich die akzeptierte Antwort sein
rinogo
14

Sie könnten es sogar auf ein Objekt prototypisieren:

Object.prototype.iterateSorted = function(worker)
{
    var keys = [];
    for (var key in this)
    {
        if (this.hasOwnProperty(key))
            keys.push(key);
    }
    keys.sort();

    for (var i = 0; i < keys.length; i++)
    {
        worker(this[ keys[i] ]);
    }
}

und die Verwendung:

var myObj = { a:1, b:2 };
myObj.iterateSorted(function(value)
{
    alert(value);
} 
Luke Schafer
quelle
3
Ich habe diese Antwort positiv bewertet, sie schien ziemlich gut zu sein, aber es stellte sich heraus, dass sie jquery :( stackoverflow.com/questions/1827458/… bricht und im Allgemeinen als sehr schlechte Idee angesehen wird. "Sie sollten Object.prototype niemals erweitern. Es macht weit mehr als break jQuery; es bricht die Funktion "Objekt als Hashtabellen" von Javascript vollständig. Tun Sie es nicht. Sie können John Resig fragen, und er wird Ihnen dasselbe sagen. "
msanjay
Weißt du was? Ich hasse auch Prototypen :) Ich benutze sie nie und rate aktiv von ihrer Verwendung ab. Ich habe mich vor 3,5 Jahren so gefühlt, als ich diese Antwort geschrieben habe, aber trotzdem vorgeschlagen ... danke, dass du die Informationen zur Verfügung gestellt hast. Abgesehen davon sollte es Frameworks NICHT brechen, da sie beim Iterieren von Objekten IMMER hasOwnProperty verwenden sollten
Luke Schafer
Hier ist ein Beispiel, in dem die Werte anstelle der Schlüssel zum Sortieren verwendet werden, während die key -> valueBeziehung beibehalten wird .
Xeoncross
6

Ich stimme Swingleys Antwort zu und ich denke, es ist ein wichtiger Punkt, dass viele dieser ausgefeilteren Lösungen fehlen. Wenn Sie sich nur mit den Schlüsseln im assoziativen Array befassen und alle Werte '1' sind, speichern Sie einfach die 'Schlüssel' als Werte in einem Array.

Anstatt:

var a = { b:1, z:1, a:1 };
// relatively elaborate code to retrieve the keys and sort them

Verwenden:

var a = [ 'b', 'z', 'a' ];
alert(a.sort());

Der einzige Nachteil dabei ist, dass Sie nicht feststellen können, ob ein bestimmter Schlüssel so einfach eingestellt werden kann. In dieser Antwort auf die Javascript-Funktion inArray finden Sie eine Antwort auf dieses Problem. Ein Problem bei der vorgestellten Lösung ist, dass a.hasValue('key')sie etwas langsamer sein wird als a['key']. Das kann in Ihrem Code von Bedeutung sein oder auch nicht.

Grant Wagner
quelle
3

Es gibt keine präzise Möglichkeit, die "Schlüssel" eines Javascript-Objekts direkt zu bearbeiten. Es ist nicht wirklich dafür ausgelegt. Haben Sie die Freiheit, Ihre Daten in etwas Besserem als einem normalen Objekt (oder einem Array, wie Ihr Beispielcode vorschlägt) abzulegen?

Wenn ja, und wenn Ihre Frage wie folgt umformuliert werden könnte: "Welches wörterbuchähnliche Objekt sollte ich verwenden, wenn ich die Schlüssel in sortierter Reihenfolge durchlaufen möchte?" dann könnten Sie ein Objekt wie dieses entwickeln:

var a = {
  keys : new Array(),
  hash : new Object(),
  set : function(key, value) {
    if (typeof(this.hash[key]) == "undefined") { this.keys.push(key); }
    this.hash[key] = value;
  },
  get : function(key) {
    return this.hash[key];
  },
  getSortedKeys : function() {
    this.keys.sort();
    return this.keys;
  }
};

// sample use
a.set('b',1);
a.set('z',1);
a.set('a',1);
var sortedKeys = a.getSortedKeys();
for (var i in sortedKeys) { print(sortedKeys[i]); }

Wenn Sie keine Kontrolle darüber haben, dass sich die Daten in einem regulären Objekt befinden, konvertiert dieses Dienstprogramm das reguläre Objekt in Ihr voll funktionsfähiges Wörterbuch:

a.importObject = function(object) {
  for (var i in object) { this.set(i, object); }
};

Dies war der Einfachheit halber eine Objektdefinition (anstelle einer wiederverwendbaren Konstruktorfunktion); nach Belieben bearbeiten.

Travis Wilson
quelle
2

Holen Sie sich die Schlüssel in der ersten forSchleife, sortieren Sie sie, verwenden Sie das sortierte Ergebnis in der zweiten forSchleife.

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

var b = [];
for (k in a) b.push(k);
b.sort();
for (var i = 0; i < b.length; ++i) alert(b[i]);
pts
quelle
2

Sie können die keysFunktion aus der Bibliothek underscore.js verwenden, um die Schlüssel abzurufen, und dann die sort()Array-Methode, um sie zu sortieren:

var sortedKeys = _.keys(dict).sort();

Die keysFunktion im Quellcode des Unterstrichs:

// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = nativeKeys || function(obj) {
    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    var keys = [];
    for (var key in obj) if (_.has(obj, key)) keys.push(key);
    return keys;
};    

// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
    return hasOwnProperty.call(obj, key);
};
Eugene Yarmash
quelle
0
<script type="text/javascript">
    var a = {
        b:1,
        z:1,
        a:1
    }; // your JS Object
    var keys = [];
    for (key in a) {
        keys.push(key);
    }
    keys.sort();
    var i = 0;
    var keyslen = keys.length;
    var str = '';
    //SORTED KEY ITERATION
    while (i < keyslen) {
        str += keys[i] + '=>' + a[keys[i]] + '\n';
        ++i;
    }
    alert(str);
    /*RESULT:
    a=>1
    b=>1
    z=>1
    */
</script>
Fran Corpier
quelle
0

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;


var keys=Object.keys(a).sort();
for(var i=0,key=keys[0];i<keys.length;key=keys[++i]){
  document.write(key+' : '+a[key]+'<br>');
}

Vlad V.
quelle
0

Ich mag die Prototypenidee von @ luke-schafer sehr, höre aber auch, was er über die Probleme mit Prototypen sagt. Was ist mit einer einfachen Funktion?

function sortKeysAndDo( obj, worker ) {
  var keys = Object.keys(obj);
  keys.sort();
  for (var i = 0; i < keys.length; i++) {
     worker(keys[i], obj[keys[i]]);
  }
}

function show( key, value ) {
  document.write( key + ' : ' + value +'<br>' );
}

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

sortKeysAndDo( a, show);

var my_object = { 'c': 3, 'a': 1, 'b': 2 };

sortKeysAndDo( my_object, show);

Dies scheint die Probleme mit Prototypen zu beseitigen und dennoch einen sortierten Iterator für Objekte bereitzustellen. Ich bin jedoch kein wirklicher JavaScript-Guru, daher würde ich gerne wissen, ob diese Lösung versteckte Fehler aufweist, die ich verpasst habe.

E FC
quelle