objetos - Iterar sobre una matriz asociativa de Javascript en orden ordenado
foreach javascript (10)
Digamos que tengo una matriz asociativa de Javascript (también conocida como hash, también conocido como diccionario):
var a = new Array();
a[''b''] = 1;
a[''z''] = 1;
a[''a''] = 1;
¿Cómo puedo iterar sobre las claves en orden ordenado? Si ayuda a simplificar las cosas, ni siquiera necesito los valores (todos son solo el número 1).
Estoy de acuerdo con la respuesta de Swingley , y creo que es un punto importante que faltan muchas de estas soluciones más elaboradas. 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
Utilizar:
var a = [ ''b'', ''z'', ''a'' ];
alert(a.sort());
El único inconveniente de esto es que no puede determinar si una clave específica está configurada tan fácilmente. Consulte esta respuesta a la función javascript en Array para obtener 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.
No hay una forma concisa de 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 teclas en orden ordenado?" entonces podrías desarrollar un objeto como este:
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 control sobre el hecho de que los datos están en un objeto normal, esta utilidad convertiría el objeto normal 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.
No puede iterar sobre ellos directamente, pero puede encontrar todas las claves y luego 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. Realmente solo lo estás usando como un objeto y debes crearlo así:
var a = {};
a["key"] = "value";
Obtenga las claves en el primer ciclo for
, ordene, use el resultado ordenado en el segundo ciclo 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]);
Puede usar el Object.keys incorporado Object.keys :
var sorted_keys = Object.keys(a).sort()
(Nota: esto no funciona en navegadores muy antiguos que no son compatibles con EcmaScript5, especialmente IE6, 7 y 8. Para obtener estadísticas actualizadas y detalladas, consulte esta tabla )
Puede usar la función de keys
de la biblioteca underscore.js para obtener las claves, y luego el método de matriz sort()
para ordenarlas:
var sortedKeys = _.keys(dict).sort();
Las keys
funcionan en el código fuente del subrayado:
// 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);
};
Realmente me gusta la idea de prototipo de @ luke-schafer, pero también escucho lo que dice sobre 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 los prototipos y aún proporciona un iterador ordenado para los objetos. Aunque no soy un gurú de JavaScript, me encantaría saber si esta solución tiene fallas ocultas que me perdí.
incluso podrías prototiparlo en un 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);
}
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>'');
}
<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>