2009-05-20 12 views
102

Digamos que tiene una matriz de JavaScript asociativa (hash de alias, diccionario alias):Iterar sobre una matriz asociativa Javascript en orden clasificado

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

¿Cómo puedo iterar sobre las teclas en el orden establecido? Si ayuda a simplificar las cosas, ni siquiera necesito los valores (todos son solo el número 1).

+10

¿por qué está usando la nueva construcción Array() y luego la está usando como un objeto? –

+0

@Luke ... Al principio también hice esto, viniendo de un fondo de PHP. Ahora lo he aprendido :) – alex

+19

@Luke: porque no tengo experiencia, parece. ¿Puedes publicar la forma correcta en una respuesta? – mike

Respuesta

121

No puede iterar sobre ellos directamente, pero puede encontrar todas las claves y luego simplemente ordenarlas.

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

Sin embargo, no es necesario convertir la variable 'a' en una matriz. Usted está realmente sólo lo utilizan como un objeto y debe crear de esta manera:

var a = {}; 
a["key"] = "value"; 
+28

Siempre debe verificar en el bucle 'for' si' obj.hasOwnProperty (clave) '. –

+0

Funciona para mí. –

+3

@Lalit: si te refieres al comentario de Torok, es porque no tienes nada que interfiera con el prototipo del objeto, en el que no puedes confiar. –

2

Obtenga las claves en el primer bucle for, ordénelo, utilice el resultado ordenado en el segundo bucle for.

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]); 
+2

usando para (k en b) en una matriz causará problemas. Iterar con un número entero –

+0

Me temo que en la última línea que quería iterar sobre la matriz 'b', y no' k' que utilizó para mantener el valor actual de la matriz 'a'. –

+0

Gracias por todas las correcciones. – pts

14

incluso se podría crear prototipos que en objeto:

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

y el uso:

var myObj = { a:1, b:2 }; 
myObj.iterateSorted(function(value) 
{ 
    alert(value); 
} 
+1

Como JavaScript distingue entre mayúsculas y minúsculas, debe escribir en mayúscula la palabra 'object', porque' typeof object // undefined'. –

+0

sí. eso fue un error tipográfico :) –

+0

Corrección de sintaxis: 'hasOwnProperty' es una función, por lo que requiere paréntesis, no corchetes. No se me permitió hacer una edición tan pequeña. –

3

Hay no es una forma concisa para manipular directamente las "claves" de un objeto Javascript. En realidad, no está diseñado para eso. ¿Tiene la libertad de poner sus datos en algo mejor que un objeto común (o una matriz, como sugiere el código de muestra)?

Si es así, y si su pregunta pudiera reformularse como "¿Qué objeto similar a un diccionario debería usar si quiero iterar sobre las claves en orden ordenado?" entonces es posible que el desarrollo de un objeto como éste:

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

Si no tiene ningún control sobre el hecho de que los datos están en un objeto de regular, esta utilidad sería convertir el objeto de regular a su diccionario completamente funcional:

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

Esta fue una definición de objeto (en lugar de una función de constructor reutilizable) para simplificar; editar a voluntad.

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

Estoy de acuerdo con Swingley's answer, y creo que es un punto importante que muchas de estas soluciones más elaboradas se echa en falta. Si solo le interesan las teclas de la matriz asociativa y todos los valores son '1', simplemente almacene las 'claves' como valores en una matriz.

En lugar de:

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

Uso:

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

El único inconveniente de esto es que no se puede determinar si una clave específica se establece con la misma facilidad. Ver this answer a javascript function inArray para una respuesta a ese problema. Un problema con la solución presentada es que a.hasValue('key') va a ser un poco más lento que a['key']. Eso puede o no importar en tu código.

121

Puede utilizar el Object.keys incorporado en el método:

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

(Nota: esto no funciona en navegadores muy antiguos no apoyar ECMAScript5, especialmente IE6, 7 y 8. Por detalladas hasta al día estadísticas, ver this table)

+5

¿Por qué esta respuesta no tiene más votos positivos? – michael667

+0

@ michael667 Probablemente porque IE 7 y 8 todavía se usan ampliamente (desafortunadamente, gracias MS) –

+1

IE7 está en 0.5% e IE8 está en 8% a partir de ahora, afortunadamente. – molnarg

2

Usted puede utilizar la función de la biblioteca keysunderscore.js para conseguir las llaves, entonces el método sort() matriz para clasificarlos:

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

La función keys en el código fuente del guión:

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

0

me gusta mucho la idea de prototipo de @ Lucas-Schäfer, sino también escuchar lo que está diciendo acerca de los problemas con los prototipos . ¿Qué hay de usar una función simple?

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

Esto parece eliminar los problemas con prototipos y aún así proporcionar un iterador clasifican para objetos. Aunque no soy un gurú de JavaScript, me encantaría saber si esta solución tiene fallas ocultas que me perdí.

Cuestiones relacionadas