Tengo la matriz asociativa:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
¿Cuál es la forma más elegante de ordenar (descender) por sus valores donde el resultado sería una matriz con los índices respectivos en este orden:
sub2, sub3, sub1, sub4, sub0
javascript
arrays
sorting
associative
John Smith
fuente
fuente
Respuestas:
Javascript no tiene "matrices asociativas" de la forma en que las piensa. En su lugar, simplemente tiene la capacidad de establecer las propiedades del objeto utilizando una sintaxis similar a una matriz (como en su ejemplo), además de la capacidad de iterar sobre las propiedades de un objeto.
El resultado de esto es que no hay garantía en cuanto al orden en el que itera sobre las propiedades, por lo que no hay nada como una clasificación para ellas. En su lugar, deberá convertir las propiedades de su objeto en una matriz "verdadera" (que garantiza el orden). Aquí hay un fragmento de código para convertir un objeto en una matriz de dos tuplas (matrices de dos elementos), clasificarlo como lo describe y luego iterar sobre él:
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 }
Puede que le resulte más natural envolver esto en una función que reciba una devolución de llamada:
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>
fuente
En lugar de corregirlo en la semántica de una 'matriz asociativa', creo que esto es lo que quiere:
function getSortedKeys(obj) { var keys = keys = Object.keys(obj); return keys.sort(function(a,b){return obj[b]-obj[a]}); }
para navegadores realmente antiguos , use esto en su lugar:
function getSortedKeys(obj) { var keys = []; for(var key in obj) keys.push(key); return keys.sort(function(a,b){return obj[b]-obj[a]}); }
Vuelves un objeto (como el tuyo) y obtienes una matriz de claves - eh propiedades - ordenadas de forma descendente por el valor (numérico) de los valores, eh, del, eh, objeto.
Esto solo funciona si sus valores son numéricos. Modifique lo poco que
function(a,b)
hay para cambiar el mecanismo de clasificación para que funcione de forma ascendente o trabaje porstring
valores (por ejemplo). Dejado como ejercicio para el lector.fuente
Discusión continua y otras soluciones cubiertas en ¿Cómo ordenar una matriz (asociativa) por valor? con la mejor solución (para mi caso) siendo saml (citado a continuación).
Las matrices solo pueden tener índices numéricos. Debería volver a escribir esto como un objeto o una matriz de objetos.
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});
Si te gusta el
status.push
método, puedes ordenarlo con:status.sort(function(a,b) { return a.val - b.val; });
fuente
sort()
trata de manera diferente. Me confundió durante una hora hasta que encontré este stackoverflow.com/questions/6712034/… Ejemplo;a.name.toLowerCase() > b.name.toLowerCase()
Realmente no existe tal cosa como una "matriz asociativa" en JavaScript. Lo que tienes ahí es solo un objeto antiguo. Funcionan como matrices asociativas, por supuesto, y las claves están disponibles, pero no hay semántica en torno al orden de las claves.
Puede convertir su objeto en una matriz de objetos (pares clave / valor) y ordenar eso:
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; }
Entonces llamarías a eso con una función comparadora.
fuente
Aquí hay una variación de la respuesta de ben blank, si no le gustan las tuplas.
Esto le ahorra algunos caracteres.
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. }
fuente
No se requieren complicaciones innecesarias ...
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; }
fuente
var stuff = {"a":1 , "b":3 , "c":0 } sortMapByValue(stuff) [Array[2], Array[2], Array[2]]
utilizo $ .each de jquery pero puedes hacerlo con un bucle for, una mejora es esta:
//.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; } };
Entonces ahora puedes hacer
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);
fuente
El mejor enfoque para el caso específico aquí, en mi opinión, es el que sugirió commonpike . Una pequeña mejora que sugiero que funciona en los navegadores modernos es:
// aao is the "associative array" you need to "sort" Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
Esto podría aplicarse fácilmente y funcionar muy bien en el caso específico aquí para que pueda hacer:
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]] }
Además de esto, proporciono aquí una función más "genérica" que puede usar para ordenar incluso en una gama más amplia de situaciones y que mezcla la mejora que acabo de sugerir con los enfoques de las respuestas de Ben Blank (ordenando también valores de cadena) y PopeJohnPaulII ( ordenando por campo / propiedad de objeto específico) y le permite decidir si desea un orden ascendente o descendente, aquí está:
// 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}); } } }
Puede probar las funcionalidades probando algo como el siguiente código:
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 */
Como ya dije, puede recorrer las claves ordenadas si necesita hacer cosas
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]] }
Por último, pero no menos importante, algunas referencias útiles a Object.keys y Array.sort
fuente
Solo para que esté disponible y alguien esté buscando tipos basados en tuplas. Esto comparará el primer elemento del objeto en la matriz, el segundo elemento y así sucesivamente. es decir, en el ejemplo siguiente, se comparará primero por "a", luego por "b" y así sucesivamente.
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))
SALIDAS
[ { 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 } ]
fuente
La respuesta de @ commonpike es "la correcta", pero como continúa comentando ...
Sí ...
Object.keys()
es mucho mejor .Pero, ¿qué es aún mejor ? ¡Duh, ya está
coffeescript
!sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b] sortedKeys 'a' : 1 'b' : 3 'c' : 4 'd' : -1
fuente