J'ai un tableau d'objets à trier. Chaque objet a deux paramètres: Force et Nom.
objects = []
object[0] = {strength: 3, name: "Leo"}
object[1] = {strength: 3, name: "Mike"}
Je veux trier d'abord par force, puis par nom alphabétiquement. J'utilise le code suivant pour trier par le premier paramètre. Comment puis-je trier alors à la seconde?
function sortF(ob1,ob2) {
if (ob1.strength > ob2.strength) {return 1}
else if (ob1.strength < ob2.strength){return -1}
return 0;
};
Merci de votre aide.
Développez votre fonction de tri pour être comme ça;
function sortF(ob1,ob2) {
if (ob1.strength > ob2.strength) {
return 1;
} else if (ob1.strength < ob2.strength) {
return -1;
}
// Else go to the 2nd item
if (ob1.name < ob2.name) {
return -1;
} else if (ob1.name > ob2.name) {
return 1
} else { // nothing to split them
return 0;
}
}
Une comparaison <
et >
sur des chaînes est une comparaison alphabétique.
Cette petite fonction est souvent utile pour trier plusieurs clés:
cmp = function(a, b) {
if (a > b) return +1;
if (a < b) return -1;
return 0;
}
ou, plus concis,
cmp = (a, b) => a > b - a < b
Appliquez-le comme ceci:
array.sort(function(a, b) {
return cmp(a.strength,b.strength) || cmp(a.name,b.name)
})
Il manque vraiment Javascript à l'opérateur Ruby - du vaisseau spatial , ce qui rend ces comparaisons extrêmement élégantes.
Vous pouvez chaîner l'ordre de tri avec un OU logique.
objects.sort(function (a, b) {
return a.strength - b.strength || a.name.localeCompare(b.name);
});
Lorsque je cherchais une réponse à cette question, les réponses que j'ai trouvées sur StackOverflow n'étaient pas vraiment celles que j'espérais. J'ai donc créé une fonction simple et réutilisable qui fait exactement cela. Cela vous permet d'utiliser le standard Array.sort, mais avec le style firstBy (). ThenBy (). ThenBy () . https://github.com/Teun/thenBy.js
PS. C'est la deuxième fois que je poste ceci. La première fois a été supprimée par un modérateur: "Ne faites pas de messages promotionnels pour votre propre travail". Je ne suis pas sûr de savoir quelles sont les règles ici, mais j'essayais de répondre à cette question. Je suis vraiment désolé que ce soit mon propre travail. N'hésitez pas à supprimer à nouveau, mais s'il vous plaît dirigez-moi à la règle en cause alors.
function sortF(ob1,ob2) {
if (ob1.strength > ob2.strength) {return 1}
else if (ob1.strength < ob2.strength) {return -1}
else if (ob1.name > ob2.name) {return 1}
return -1;
};
EDIT: Triez par force, puis si force est égale, triez par nom . Le cas où force et nom sont égaux dans les deux objets n'a pas besoin d'être pris en compte séparément relation -à-ou-égale-à. Le résultat du tri sera correct. Cela pourrait accélérer ou ralentir, je ne sais pas. Si vous voulez être explicite, remplacez simplement
return -1;
avec
else if (ob1.name < ob2.name) {return -1}
return 0;
la réponse de steve, mais plus jolie.
objects.sort(function(a,b)
{
if(a.strength > b.strength) {return 1;}
if(a.strength < b.strength) {return -1;}
if(a.name > b.name ) {return 1;}
if(a.name < b.name ) {return -1;}
return 0;
}
Trouvez la fonction 'sortFn' ci-dessous. Cette fonction trie par nombre illimité de paramètres (comme dans c #: SortBy (...). ThenBy (...). ThenByDesc (...)).
function sortFn() {
var sortByProps = Array.prototype.slice.call(arguments),
cmpFn = function(left, right, sortOrder) {
var sortMultiplier = sortOrder === "asc" ? 1 : -1;
if (left > right) {
return +1 * sortMultiplier;
}
if (left < right) {
return -1 * sortMultiplier;
}
return 0;
};
return function(sortLeft, sortRight) {
// get value from object by complex key
var getValueByStr = function(obj, path) {
var i, len;
//prepare keys
path = path.replace('[', '.');
path = path.replace(']', '');
path = path.split('.');
len = path.length;
for (i = 0; i < len; i++) {
if (!obj || typeof obj !== 'object') {
return obj;
}
obj = obj[path[i]];
}
return obj;
};
return sortByProps.map(function(property) {
return cmpFn(getValueByStr(sortLeft, property.prop), getValueByStr(sortRight, property.prop), property.sortOrder);
}).reduceRight(function(left, right) {
return right || left;
});
};
}
var arr = [{
name: 'marry',
LocalizedData: {
'en-US': {
Value: 10000
}
}
}, {
name: 'larry',
LocalizedData: {
'en-US': {
Value: 2
}
}
}, {
name: 'marry',
LocalizedData: {
'en-US': {
Value: 100
}
}
}, {
name: 'larry',
LocalizedData: {
'en-US': {
Value: 1
}
}
}];
document.getElementsByTagName('pre')[0].innerText = JSON.stringify(arr)
arr.sort(sortFn({
prop: "name",
sortOrder: "asc"
}, {
prop: "LocalizedData[en-US].Value",
sortOrder: "desc"
}));
document.getElementsByTagName('pre')[1].innerText = JSON.stringify(arr)
pre {
font-family: "Courier New" Courier monospace;
white-space: pre-wrap;
}
Before:
<pre></pre>
Result:
<pre></pre>
Que diriez-vous d'un inliner long et puissant:
const orderByMultipleFactory = (fields) => (a, b) => fields.reduce((acc, {name, asc = true, compareFn}) => acc || (compareFn ? compareFn(a, b) : (isString(a[name]) ? (asc ? a[name].localeCompare(b[name]) : b[name].localeCompare(a[name])) : (asc ? a[name] - b[name] : b[name] - a[name]))), 0);
Fields est un tableau d'objets avec le champ name
qui spécifie la propriété de object, puis les options facultatives asc
et compareFn
pour contrôler la direction ou remplacer la méthode de comparaison par défaut.
Par défaut, les chaînes sont comparées par localCompare
et le reste par simple a - b
.
Exemple:
[{a: 2, b: 'y'}, {a: 3, b: 'x'}, {a: 2, b: 'z'}]
.sort(orderByMultipleFactory([{name: 'a', asc: false}, {name: 'b'}]))
// result is sorted by "a" descending and equal records by "b" ascending.
En 2018, vous pouvez utiliser simplement la fonction sort () ES6, qui fait exactement ce que vous voulez https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array /Trier
Avec ES6, vous pouvez faire
array.sort(function(a, b) {
return SortFn(a.strength,b.strength) || SortFn(a.name,b.name)
})
private sortFn(a, b): number {
return a === b ? 0 : a < b ? -1 : 1;
}