Comment trier un tableau JavaScript d'objets par une propriété d'objet imbriquée?

J'ai cette fonction pour trier un tableau JavaScript d'objets en fonction d'une propriété:

// arr is the array of objects, prop is the property to sort by var sort = function (prop, arr) { arr.sort(function (a, b) { if (a[prop] < b[prop]) { return -1; } else if (a[prop] > b[prop]) { return 1; } else { return 0; } }); }; 

Cela fonctionne avec des tableaux comme celui-ci:

 sort('property', [ {property:'1'}, {property:'3'}, {property:'2'}, {property:'4'}, ]); 

Mais je veux pouvoir trier aussi par des propriétés imbriquées, par exemple quelque chose comme:

 sort('nestedobj.property', [ {nestedobj:{property:'1'}}, {nestedobj:{property:'3'}}, {nestedobj:{property:'2'}}, {nestedobj:{property:'4'}} ]); 

Cependant, cela ne fonctionne pas car il n'est pas possible de faire quelque chose comme object['nestedobj.property'] , il devrait être object['nestedobj']['property'] .

Savez-vous comment puis-je résoudre ce problème et faire fonctionner ma fonction avec les propriétés des objets imbriqués?

Merci d'avance

Vous pouvez diviser le prop . , Et iterate sur le tableau de mise à jour de a et b avec la propriété imbriquée suivante au cours de chaque itération.

Exemple: http://jsfiddle.net/x8KD6/1/

 var sort = function (prop, arr) { prop = prop.split('.'); var len = prop.length; arr.sort(function (a, b) { var i = 0; while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; } if (a < b) { return -1; } else if (a > b) { return 1; } else { return 0; } }); return arr; }; 

Au lieu de passer la propriété en tant que chaîne, passez une fonction qui peut récupérer la propriété à partir de l'objet de niveau supérieur.

 var sort = function (propertyRetriever, arr) { arr.sort(function (a, b) { var valueA = propertyRetriever(a); var valueB = propertyRetriever(b); if (valueA < valueB) { return -1; } else if (valueA > valueB) { return 1; } else { return 0; } }); }; 

Invoquer comme,

 var simplePropertyRetriever = function(obj) { return obj.property; }; sort(simplePropertyRetriever, { .. }); 

Ou en utilisant un objet imbriqué,

 var nestedPropertyRetriever = function(obj) { return obj.nestedObj.property; }; sort(nestedPropertyRetriever, { .. }); 

Vous pouvez utiliser Agile.js pour ce genre de choses.
En fait, vous passez une expression au lieu d'un rappel, il gère les propriétés imbriquées et l'expression javascript d'une manière très agréable.

Utilisation: _.orderBy(array, expression/callback, reverse[optional])

Exemple:

 var orders = [ { product: { price: 91.12, id: 1 }, date: new Date('01/01/2014') }, { product: { price: 79.21, id: 2 }, date: new Date('01/01/2014') }, { product: { price: 99.90, id: 3 }, date: new Date('01/01/2013') }, { product: { price: 19.99, id: 4 }, date: new Date('01/01/1970') } ]; _.orderBy(orders, 'product.price'); // → [orders[3], orders[1], orders[0], orders[2]] _.orderBy(orders, '-product.price'); // → [orders[2], orders[0], orders[1], orders[3]] 

Cela répondrait-il à vos besoins?

 // arr is the array of objects, prop is the property to sort by var sort = function (nestedObj, prop, arr) { arr.sort(function (a, b) { if (a[nestedObj][prop] < b[nestedObj][prop]) { return -1; } else if (a[nestedObj][prop] > b[nestedObj][prop]) { return 1; } else { return 0; } }); }; 

Essayez ceci (utilisez une fonction récursive pour obtenir une valeur imbriquée, vous pouvez passer la propriété imbriquée comme nestedobj.property): vous pouvez l'utiliser pour n'importe quel niveau de hiérarchie

 // arr is the array of objects, prop is the property to sort by var getProperty = function(obj, propNested){ if(!obj || !propNested){ return null; } else if(propNested.length == 1) { var key = propNested[0]; return obj[key]; } else { var newObj = propNested.shift(); return getProperty(obj[newObj], propNested); } }; var sort = function (prop, arr) { arr.sort(function (a, b) { var aProp = getProperty(a, prop.split(".")); var bProp = getProperty(a, prop.split(".")); if (aProp < bProp) { return -1; } else if (aProp > bProp) { return 1; } else { return 0; } }); }; 

C'est mon code de modification.

 // arr is the array of objects, prop is the property to sort by var s = function (prop, arr) { // add sub function for get value from obj (1/2) var _getVal = function(o, key){ var v = o; var k = key.split("."); for(var i in k){ v = v[k[i]]; } return v; } return arr.sort(function (a, b) { // get value from obj a, b before sort (2/2) var aVal = _getVal(a, prop); var bVal = _getVal(b, prop); if (aVal < bVal) { return -1; } else if (aVal > bVal) { return 1; } else { return 0; } }); }; 

Utilisez Array.prototype.sort() avec une fonction de comparaison personnalisée pour effectuer le tri descendant d'abord:

 champions.sort(function(a, b) { return b.level - a.level }).slice(... 

Encore plus agréable avec ES6:

 champions.sort((a, b) => b.level - a.level).slice(...