Je trie une liste d'objets en fonction d'une variable qui y est stockée. Nommons cette variable "sortCriteria"
Un exemple d'ensemble de valeurs "sortCriteria" pour différents objets:
400, 329, 529, "String1", 678, "String2", 588, "String3", "String1", 201, "String2"
Donc, en gros, il y a 4 types de valeurs que je peux obtenir dans "sortCriteria":
1. Une valeur numérique
2. String1
3. String2
4. String3
Maintenant, je dois trier ces données de manière à ce que les données numériques aient la priorité la plus élevée, puis "String1", puis "String2" et ensuite "String3". c'est-à-dire
Priorité de (Numérique> Chaîne1> Chaîne2> Chaîne3)
Notez que, en sortie, toutes ces valeurs numériques doivent être triées.
Par conséquent, l'ordre trié des exemples de données serait -
201, 329, 400, 529, 588, 678, "Chaîne1", "Chaîne1", "Chaîne2", "Chaîne2", "Chaîne3".
En outre, si plusieurs objets ont les mêmes valeurs "sortCriteria", leur ordre doit être conservé.
Par exemple.
Disons que j'ai 2 objets dont la valeur "sortCriteria" est la même
Objet 1: 205,
Objet 2: 205.
Ensuite, dans l'ordre trié, Object1 doit venir avant Object2.
Ma mise en œuvre Javascript actuelle de la logique de tri spécifique ressemble à ceci:
function mySortRule(a, b) {
var value1 = a[1], value2 = b[1];
var value1Priority = getPriorityOf(value1);
var value2Priority = getPriorityOf(value2);
return value1Priority - value2Priority;
}
function getPriorityOf(value) {
var priority;
if(value!="String1" && value!="String2" && value!="String3") {
priority = value;
}
else if(value == "String1") {
priority = Number.MAX_VALUE-2;
}
else if(value == "String2") {
priority = Number.MAX_VALUE-1;
}
else if(value == "String3") {
priority = Number.MAX_VALUE;
}
return priority;
}
sortCriteriaArray.sort(mySortRule);
La valeur sortCriteriaArray [i] est dans ce format: ["indexOfObject", "sortCriteria"]
Cette solution fonctionne en quelque sorte mais ne conserve pas l'ordre des objets. De plus, je ne pense pas que ce soit une bonne approche car -
1. Demain, disons que nous devrons insérer d'autres types de cordes. Dans ce cas, nous devrons changer ces instructions conditionnelles dans la fonction getPriorityOf ().
2. L'utilisation de "Number.MAX_VALUE" pour définir la priorité me semble piratée.
Y a-t-il un meilleur moyen d'y parvenir?
4 Réponses :
Jetez un œil à ma solution et vérifiez si elle convient:
// Array
const arr = [400, 329, 529, "String1", 678, "String2", 588, "String3", "String1", 201, "String2"];
// Filter methods
const isNumber = (item) => !isNaN(item);
const checkString = (str) => (item) => item === str;
// Sort/Config method
const sortPriority = () => {
return [
...arr.filter(isNumber).sort((a, b) => a - b),
...arr.filter(checkString("String1")),
...arr.filter(checkString("String2")),
...arr.filter(checkString("String3")),
]
}
console.log(sortPriority());
@Cid ma faute, corrigé. Thx, mec
Faites en sorte que le test de comparaison soit lexicographique, d'abord sur le type (attribution d'index de priorité tels que nombre: 0, chaîne: 1), puis sur la valeur en cas d'égalité. C'est propre et extensible.
Pour conserver l'ordre, vous devez utiliser un algorithme de tri stable tel que MergeSort.
Sinon, si vous ne prévoyez pas d'ajouter d'autres types, procédez comme suit:
parcourir la liste et la scinder (de manière stable) dans une sous-liste avec les nombres et une autre sous-liste avec les chaînes;
trier les sous-listes et les concaténer.
Oui, celui-ci me paraît plus propre. Je vais utiliser ça. Merci
Étant donné que vous avez un nombre restreint et fixe de chaînes, vous pouvez créer une règle de tri composite en utilisant un objet comme dictionnaire pour les priorités au lieu de votre getPriorityOf et vous n'avez pas à utiliser MAX_VALUE . Vous pouvez prendre un objet pour l'ordre des chaînes données ou une valeur par défaut de zéro (en supposant que les nombres sont la priorité absolue), puis trier par valeur numérique.
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = [{ index: 0, data: 400 }, { index: 1, data: 329 }, { index: 2, data: 529 }, { index: 3, data: "String1" }, { index: 4, data: 678 }, { index: 5, data: "String2" }, { index: 6, data: 588 }, { index: 7, data: "String3" }, { index: 8, data: "String1" }, { index: 9, data: 201 }, { index: 10, data: "String2" }],
indices = new WeakMap(data.map((o, i) => [o, i])),
order = { String1: 1, String2: 2, String3: 3 };
data.sort((a, b) =>
(order[a.data] || 0) - (order[b.data] || 0) || // get priority ordering
a.data - b.data || // order by number
indices.get(a) - indices.get(b) // keep same values in order
);
console.log(data);
Malheureusement, la stabilité de Array.sort n'est pas garantie, bien que souvent en pratique elle le soit. Voir aussi À propos de la stabilité de l'algorithme utilisé par le moteur V8
Si il n'est pas stable dans votre environnement, vous pouvez émuler un tri stable en utilisant un WeakMap pour stocker les positions d'origine.
Le fait que vous demandiez de la stabilité implique que vous avez vraiment des objets que vous voulez trier par certains champ. Je suppose que ce champ appelé data . Notez que la propriété index n'est pas utilisée par l'algorithme, c'est dans cet exemple uniquement pour prouver la stabilité de la commande.
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = [400, 329, 529, "String1", 678, "String2", 588, "String3", "String1", 201, "String2"],
order = { String1: 1, String2: 2, String3: 3 };
data.sort((a, b) => (order[a] || 0) - (order[b] || 0) || a - b);
console.log(data);
J'aime ce code pour plus de simplicité, mais est-ce que la spécification de Array.sort nécessite un algorithme stable pour être utilisé? Cela semble être une chose dont le PO se plaint
Mais c'est exactement l'un des problèmes dont OP se plaint à " De plus, si plusieurs objets ont les mêmes valeurs" sortCriteria ", leur ordre doit être conservé. " et encore " Cette solution est fonctionne mais ne conserve pas l’ordre des objets. "
le résultat dépend d'une implémentation stable de l'algorithme de tri ou si un autre paramètre est utilisé pour garder l'ordre.
En d'autres termes, est-ce que je comprends bien que cette réponse ne couvre pas vraiment le problème réel du PO?
Autant que j'ai lu la question, l'OP a déjà un code qui fonctionne mais il y a deux choses qu'il n'aime pas: 1. le tri des résultats n'est pas stable 2. le code n'est pas à l'épreuve du temps. Ai-je raison de dire que vous êtes en quelque sorte l'adresse n ° 2 mais que vous ne vous adressez pas du tout au n ° 1?
veuillez regarder la deuxième section.
continuons cette discussion dans le chat .
function mySortRule(a, b) {
function getPriorityOf(value) {
// priority order..
return [Boolean, Number, String, Array, Object, Function]
.reverse().indexOf(value.constructor);
}
// smallest first..
return getPriorityOf(a) == getPriorityOf(b) ?
(a.valueOf() == b.valueOf() ?
0 :
(a.valueOf() > b.valueOf() ? 1 : -1)) :
getPriorityOf(b) - getPriorityOf(a)
}
var sortCriteriaArray =
[400, 329, 529, "String1", 678, "String2", 588, "String3", "String1", 201, "String2"];
sortCriteriaArray.sort(mySortRule);
// -> [201, 329, 400, 529, 588, 678, "String1", "String1", "String2", "String2", "String3"]
(Assuming every array element is neither null or undefined)
Vérifiez le type. si les deux sont numériques ou les deux sont des chaînes, utilisez une comparaison régulière (
"String1" <"String2"il est trié par ordre alphabétique). sinon, le plus bas est le numérique.vous ne pouvez pas trier les objets avec des nombres (32 bits positifs, comme indices pour les tableaux) comme clé, tant que ces nombres ne sont pas dans l'ordre.
pourquoi cela n'aide pas? stackoverflow.com/a/54310041/10761855