J'ai un tableau d'objets JavaScript:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
Comment puis-je les trier par la valeur de last_nom
en JavaScript?
Je connais sort(a,b)
, mais cela ne semble fonctionner que sur les chaînes et les nombres. Dois-je ajouter une méthode toString()
à mes objets?
C'est assez facile d'écrire votre propre fonction de comparaison:
function compare( a, b ) {
if ( a.last_nom < b.last_nom ){
return -1;
}
if ( a.last_nom > b.last_nom ){
return 1;
}
return 0;
}
objs.sort( compare );
Ou en ligne (c/o Marco Demaio):
objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0));
Vous pouvez également créer une fonction de tri dynamique qui trie les objets en fonction de la valeur que vous transmettez:
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
/* next line works with strings and numbers,
* and you may want to customize it to your needs
*/
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
Donc, vous pouvez avoir un tableau d'objets comme celui-ci:
var People = [
{Name: "Name", Surname: "Surname"},
{Name:"AAA", Surname:"ZZZ"},
{Name: "Name", Surname: "AAA"}
];
... et ça marchera quand vous ferez:
People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));
En fait, cela répond déjà à la question. La partie ci-dessous est écrite parce que beaucoup de gens m'ont contacté, se plaignant que cela ne fonctionne pas avec plusieurs paramètres .
Vous pouvez utiliser la fonction ci-dessous pour générer des fonctions de tri avec plusieurs paramètres de tri.
function dynamicSortMultiple() {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
Ce qui vous permettrait de faire quelque chose comme ça:
People.sort(dynamicSortMultiple("Name", "-Surname"));
Pour les plus chanceux parmi nous qui peuvent utiliser ES6, ce qui permet d'étendre les objets natifs:
class MyArray extends Array {
sortBy(...args) {
return this.sort(dynamicSortMultiple.apply(null, args));
}
}
Cela permettrait ceci:
MyArray.from(People).sortBy("Name", "-Surname");
Dans ES6/ES2015 ou version ultérieure, vous pouvez procéder comme suit:
objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
utilisez le trait de soulignement, son petit et génial ...
sortBy_.sortBy (list, iterator, [context]) Retourne une copie triée de la liste, classée par ordre croissant en fonction des résultats de l'exécution de chaque valeur via l'itérateur. Itérateur peut également être le nom de chaîne de la propriété à trier (par exemple, longueur).
var objs = [
{ first_nom: 'Lazslo',last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
var sortedObjs = _.sortBy( objs, 'first_nom' );
Ne comprenez pas pourquoi les gens compliquent les choses:
objs.sort(function(a, b){
return a.last_nom > b.last_nom;
});
Pour les moteurs plus stricts:
objs.sort(function(a, b){
return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});
Échangez l'opérateur pour le faire trier par ordre alphabétique inverse.
Si vous avez des noms en double, vous pouvez les trier par prénom.
obj.sort(function(a,b){
if(a.last_nom< b.last_nom) return -1;
if(a.last_nom >b.last_nom) return 1;
if(a.first_nom< b.first_nom) return -1;
if(a.first_nom >b.first_nom) return 1;
return 0;
});
Solution simple et rapide à ce problème en utilisant un héritage de prototype:
Array.prototype.sortBy = function(p) {
return this.slice(0).sort(function(a,b) {
return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
});
}
Exemple/Utilisation
objs = [{age:44,name:'vinay'},{age:24,name:'deepak'},{age:74,name:'suresh'}];
objs.sortBy('age');
// Returns
// [{"age":24,"name":"deepak"},{"age":44,"name":"vinay"},{"age":74,"name":"suresh"}]
objs.sortBy('name');
// Returns
// [{"age":24,"name":"deepak"},{"age":74,"name":"suresh"},{"age":44,"name":"vinay"}]
pdate: Ne modifie plus le tableau d'origine.
A partir de 2018, il existe une solution beaucoup plus courte et élégante. Il suffit d'utiliser. Array.prototype.sort () .
Exemple:
var items = [
{ name: 'Edward', value: 21 },
{ name: 'Sharpe', value: 37 },
{ name: 'And', value: 45 },
{ name: 'The', value: -12 },
{ name: 'Magnetic', value: 13 },
{ name: 'Zeros', value: 37 }
];
// sort by value
items.sort(function (a, b) {
return a.value - b.value;
});
Au lieu d'utiliser une fonction de comparaison personnalisée, vous pouvez également créer un type d'objet avec la méthode personnalisée toString()
(appelée par la fonction de comparaison par défaut):
function Person(firstName, lastName) {
this.firtName = firstName;
this.lastName = lastName;
}
Person.prototype.toString = function() {
return this.lastName + ', ' + this.firstName;
}
var persons = [ new Person('Lazslo', 'Jamf'), ...]
persons.sort();
Vous pouvez utiliser
( https://lodash.com/docs/4.17.10#orderBy )
Cette méthode s'apparente à _.sortBy, sauf qu'elle permet de spécifier les ordres de tri des itérés à trier. Si les commandes ne sont pas spécifiées, toutes les valeurs sont triées par ordre croissant. Sinon, spécifiez un ordre de "desc" pour décroissant ou "asc" pour un ordre de tri croissant des valeurs correspondantes.
Arguments
collection (Array | Object): la collection sur laquelle itérer. [iteratees = [_. identity]] (Array [] | Function [] | Object [] | string []): itérations à trier. [orders] (string []): Ordre de tri des itérés.
Retourne
(Tableau): Retourne le nouveau tableau trié.
var _ = require('lodash');
var homes = [
{"h_id":"3",
"city":"Dallas",
"state":"TX",
"Zip":"75201",
"price":"162500"},
{"h_id":"4",
"city":"Bevery Hills",
"state":"CA",
"Zip":"90210",
"price":"319250"},
{"h_id":"6",
"city":"Dallas",
"state":"TX",
"Zip":"75000",
"price":"556699"},
{"h_id":"5",
"city":"New York",
"state":"NY",
"Zip":"00010",
"price":"962500"}
];
_.orderBy(homes, ['city', 'state', 'Zip'], ['asc', 'desc', 'asc']);
Lodash.js (sur-ensemble de nderscore.js )
Il est bon de ne pas ajouter de cadre à chaque simple élément de logique, mais s’appuyer sur des cadres d’utilité bien testés, accélérer le développement et réduire le nombre de bogues écrits n’est pas une honte.
Lodash produit un code très propre et promeut un style de programmation plus fonctionnel , ce qui entraîne moins de bogues. En un coup d'œil, l'intention du code devient claire.
Le problème d'OP peut être simplement résolu comme suit:
const sortedObjs = _.sortBy(objs, 'last_nom');
Plus d'informations? Par exemple. nous avons l'objet imbriqué suivant:
const users = [
{ 'user': {'name':'fred', 'age': 48}},
{ 'user': {'name':'barney', 'age': 36 }},
{ 'user': {'name':'wilma'}},
{ 'user': {'name':'betty', 'age': 32}}
];
Nous pouvons maintenant utiliser le _. Propriété raccourci user.age
pour spécifier le chemin d'accès à la propriété à rechercher. Nous allons trier les objets utilisateur en fonction de la propriété d'âge imbriquée. Oui, cela permet de faire correspondre les propriétés imbriquées!
const sortedObjs = _.sortBy(users, ['user.age']);
Voulez-vous l'inverser? Aucun problème. Utilisez _. Reverse .
const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));
Voulez-vous combiner les deux en utilisant Chaining à la place?
const sortedObjs = _.chain(users).sortBy('user.age').reverse().value();
Il y a beaucoup de bonnes réponses ici, mais je voudrais souligner qu'elles peuvent être étendues très simplement pour réaliser un tri beaucoup plus complexe. La seule chose à faire est d'utiliser l'opérateur OR pour enchaîner les fonctions de comparaison comme ceci:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
Où fn1
, fn2
, ... sont les fonctions de tri qui retournent [-1,0,1]. Il en résulte "tri par fn1", "tri par fn2" qui est à peu près égal à ORDER BY en SQL.
Cette solution est basée sur le comportement de l’opérateur ||
qui évalue le première expression évaluée pouvant être convertie en true .
Le formulaire le plus simple n'a qu'une seule fonction en ligne comme celle-ci:
// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )
Ayant deux étapes avec last_nom
, first_nom
, l'ordre de tri ressemblerait à ceci:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) ||
a.first_nom.localeCompare(b.first_nom) )
Une fonction de comparaison générique pourrait ressembler à ceci:
// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])
Cette fonction pourrait être étendue pour prendre en charge les champs numériques, la sensibilité à la casse, les types de données arbitraires, etc.
Vous pouvez les utiliser en les chaînant par ordre de priorité:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
Le point ici est que JavaScript pur avec une approche fonctionnelle peut vous prendre beaucoup de temps sans bibliothèques externes ou code complexe. Il est également très efficace, car aucune analyse de chaîne ne doit être faite
Exemple d'utilisation:
objs.sort(sortBy('last_nom'));
Scénario:
/**
* @description
* Returns a function which will sort an
* array of objects by the given key.
*
* @param {String} key
* @param {Boolean} reverse
* @return {Function}
*/
const sortBy = (key, reverse) => {
// Move smaller items towards the front
// or back of the array depending on if
// we want to sort the array in reverse
// order or not.
const moveSmaller = reverse ? 1 : -1;
// Move larger items towards the front
// or back of the array depending on if
// we want to sort the array in reverse
// order or not.
const moveLarger = reverse ? -1 : 1;
/**
* @param {*} a
* @param {*} b
* @return {Number}
*/
return (a, b) => {
if (a[key] < b[key]) {
return moveSmaller;
}
if (a[key] > b[key]) {
return moveLarger;
}
return 0;
};
};
J'ai un morceau de code qui fonctionne pour moi:
arr.sort((a, b) => a.name > b.name)
UPDATE: Ne fonctionne pas toujours, donc ce n'est pas correct :(
Je n'ai pas vu cette approche particulière suggérée, alors voici une méthode de comparaison succincte que j'aime utiliser et qui fonctionne à la fois pour string
et number
:
const objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
const sortBy = fn => (a, b) => {
const fa = fn(a)
const fb = fn(b)
return -(fa < fb) || +(fa > fb)
}
const getLastName = o => o.last_nom
const sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
Voici une explication de sortBy()
:
sortBy()
accepte une fn
qui sélectionne la valeur d'un objet à utiliser à titre de comparaison et renvoie une fonction pouvant être passée directement à Array.prototype.sort()
. Dans cet exemple, nous utilisons o.last_nom
comme valeur de comparaison. Ainsi, chaque fois que nous recevons deux objets via Array.prototype.sort()
, tels que
{ first_nom: 'Lazslo', last_nom: 'Jamf' }
et
{ first_nom: 'Pig', last_nom: 'Bodine' }
nous utilisons
(a, b) => {
const fa = fn(a)
const fb = fn(b)
return -(fa < fb) || +(fa > fb)
}
les comparer.
En nous souvenant que fn = o => o.last_nom
, nous pouvons étendre la fonction de comparaison à l’équivalent
(a, b) => {
const fa = a.last_nom
const fb = b.last_nom
return -(fa < fb) || +(fa > fb)
}
L'opérateur logique OR ||
dispose d'une fonctionnalité de court-circuit très utile ici. En raison de la façon dont cela fonctionne, le corps de la fonction ci-dessus signifie
if (fa < fb) return -1
return +(fa > fb)
Donc, si fa < fb
nous retournons -1
, sinon si fa > fb
, nous renvoyons +1
, mais si fa == fb
, alors fa < fb
et fa > fb
sont false
, donc il retourne +0
.
En prime, voici l'équivalent dans ECMAScript 5 sans les fonctions de flèche, ce qui est malheureusement plus détaillé:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
var sortBy = function (fn) {
return function (a, b) {
var fa = fn(a)
var fb = fn(b)
return -(fa < fb) || +(fa > fb)
}
}
var getLastName = function (o) { return o.last_nom }
var sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
Je sais que cette question est trop ancienne, mais je n'ai vu aucune mise en œuvre semblable à la mienne.
Cette version est basée sur le idiome de transformation de Schwartzian .
function sortByAttribute(array, ...attrs) {
// generate an array of predicate-objects contains
// property getter, and descending indicator
let predicates = attrs.map(pred => {
let descending = pred.charAt(0) === '-' ? -1 : 1;
pred = pred.replace(/^-/, '');
return {
getter: o => o[pred],
descend: descending
};
});
// schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
return array.map(item => {
return {
src: item,
compareValues: predicates.map(predicate => predicate.getter(item))
};
})
.sort((o1, o2) => {
let i = -1, result = 0;
while (++i < predicates.length) {
if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
if (result *= predicates[i].descend) break;
}
return result;
})
.map(item => item.src);
}
Voici un exemple d'utilisation:
let games = [
{ name: 'Pako', rating: 4.21 },
{ name: 'Hill Climb Racing', rating: 3.88 },
{ name: 'Angry Birds Space', rating: 3.88 },
{ name: 'Badland', rating: 4.33 }
];
// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));
Étant donné que vous rencontrez probablement des structures de données plus complexes comme ce tableau, j'élargirais la solution.
Sont la version plus pluggable basée sur @ ege-Özcan est très belle réponse .
J'ai rencontré le dessous et je ne pouvais pas le changer. Je ne voulais pas non plus aplatir l'objet temporairement. Je ne voulais pas non plus utiliser le trait de soulignement/lodash, principalement pour des raisons de performances et du plaisir de le mettre en œuvre moi-même.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
Le but est de le trier principalement par People.Name.name
et ensuite par People.Name.surname
Désormais, dans la solution de base, la notation entre crochets permet de calculer les propriétés à trier de manière dynamique. Ici, cependant, nous devrions également construire la notation entre crochets de manière dynamique, puisque vous vous attendriez à ce que certains comme People['Name.name']
fonctionnent, ce qui ne fonctionne pas.
Faire simplement People['Name']['name']
, en revanche, est statique et ne vous permet que de descendre le n - ème niveau.
Le principal ajout ici sera de parcourir l’arborescence des objets et de déterminer la valeur de la dernière feuille, que vous devez spécifier, ainsi que toute feuille intermédiaire.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
// { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
// { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]
// same logic as above, but strong deviation for dynamic properties
function dynamicSort(properties) {
var sortOrder = 1;
// determine sort order by checking sign of last element of array
if(properties[properties.length - 1][0] === "-") {
sortOrder = -1;
// Chop off sign
properties[properties.length - 1] = properties[properties.length - 1].substr(1);
}
return function (a,b) {
propertyOfA = recurseObjProp(a, properties)
propertyOfB = recurseObjProp(b, properties)
var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
return result * sortOrder;
};
}
/**
* Takes an object and recurses down the tree to a target leaf and returns it value
* @param {Object} root - Object to be traversed.
* @param {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
* @param {Number} index - Must not be set, since it is implicit.
* @return {String|Number} The property, which is to be compared by sort.
*/
function recurseObjProp(root, leafs, index) {
index ? index : index = 0
var upper = root
// walk down one level
lower = upper[leafs[index]]
// Check if last leaf has been hit by having gone one step too far.
// If so, return result from last step.
if (!lower) {
return upper
}
// Else: recurse!
index++
// HINT: Bug was here, for not explicitly returning function
// https://stackoverflow.com/a/17528613/3580261
return recurseObjProp(lower, leafs, index)
}
/**
* Multi-sort your array by a set of properties
* @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
* @return {Number} Number - number for sort algorithm
*/
function dynamicMultiSort() {
var args = Array.prototype.slice.call(arguments); // slight deviation to base
return function (a, b) {
var i = 0, result = 0, numberOfProperties = args.length;
// REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
// Consider: `.forEach()`
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(args[i])(a, b);
i++;
}
return result;
}
}
Exemple de travail sur JSBin
Une autre option:
var someArray = [...];
function generateSortFn(prop, reverse) {
return function (a, b) {
if (a[prop] < b[prop]) return reverse ? 1 : -1;
if (a[prop] > b[prop]) return reverse ? -1 : 1;
return 0;
};
}
someArray.sort(generateSortFn('name', true));
trie croissant par défaut.
Un moyen simple:
objs.sort(function(a,b) {
return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});
Voir que '.toLowerCase()'
est nécessaire pour éviter les erreurs lors de la comparaison de chaînes.
En combinant la solution dynamique d'Ege avec l'idée de Vinay, vous obtenez une solution robuste de Nice:
Array.prototype.sortBy = function() {
function _sortByAttr(attr) {
var sortOrder = 1;
if (attr[0] == "-") {
sortOrder = -1;
attr = attr.substr(1);
}
return function(a, b) {
var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
return result * sortOrder;
}
}
function _getSortFunc() {
if (arguments.length == 0) {
throw "Zero length arguments not allowed for Array.sortBy()";
}
var args = arguments;
return function(a, b) {
for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
result = _sortByAttr(args[i])(a, b);
}
return result;
}
}
return this.sort(_getSortFunc.apply(null, arguments));
}
Usage:
// Utility for printing objects
Array.prototype.print = function(title) {
console.log("************************************************************************");
console.log("**** "+title);
console.log("************************************************************************");
for (var i = 0; i < this.length; i++) {
console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
}
}
// Setup sample data
var arrObj = [
{FirstName: "Zach", LastName: "Emergency", Age: 35},
{FirstName: "Nancy", LastName: "Nurse", Age: 27},
{FirstName: "Ethel", LastName: "Emergency", Age: 42},
{FirstName: "Nina", LastName: "Nurse", Age: 48},
{FirstName: "Anthony", LastName: "Emergency", Age: 44},
{FirstName: "Nina", LastName: "Nurse", Age: 32},
{FirstName: "Ed", LastName: "Emergency", Age: 28},
{FirstName: "Peter", LastName: "Physician", Age: 58},
{FirstName: "Al", LastName: "Emergency", Age: 51},
{FirstName: "Ruth", LastName: "Registration", Age: 62},
{FirstName: "Ed", LastName: "Emergency", Age: 38},
{FirstName: "Tammy", LastName: "Triage", Age: 29},
{FirstName: "Alan", LastName: "Emergency", Age: 60},
{FirstName: "Nina", LastName: "Nurse", Age: 54}
];
//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");
paramètres de desc supplémentaire pour Ege Özcan code
function dynamicSort(property, desc) {
if (desc) {
return function (a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
}
return function (a, b) {
return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
}
}
Une fonction simple qui trie un tableau d'objets par une propriété
function sortArray(array, property, direction) {
direction = direction || 1;
array.sort(function compare(a, b) {
let comparison = 0;
if (a[property] > b[property]) {
comparison = 1 * direction;
} else if (a[property] < b[property]) {
comparison = -1 * direction;
}
return comparison;
});
return array; // Chainable
}
Usage:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc
objs.sort(function(a,b){return b.last_nom>a.last_nom})
Selon votre exemple, vous devez trier selon deux champs (nom de famille, prénom), plutôt que dans un. Vous pouvez utiliser la bibliothèque Alasql pour faire ce tri sur une seule ligne:
var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);
Essayez cet exemple sur jsFiddle .
Vous devrez peut-être les convertir en minuscules pour éviter toute confusion.
objs.sort(function (a,b) {
var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()
if (nameA < nameB)
return -1;
if (nameA > nameB)
return 1;
return 0; //no sorting
})
Étant donné l'exemple original:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
Trier par plusieurs champs:
objs.sort(function(left, right) {
var last_nom_order = left.last_nom.localeCompare(right.last_nom);
var first_nom_order = left.first_nom.localeCompare(right.first_nom);
return last_nom_order || first_nom_order;
});
Remarques
a.localeCompare(b)
est niversellement pris en charge et renvoie -1,0,1 si a<b
, a==b
, a>b
respectivement.||
à la dernière ligne donne last_nom
priorité sur first_nom
.var age_order = left.age - right.age;
return -last_nom_order || -first_nom_order || -age_order;
function compare(propName) {
return function(a,b) {
if (a[propName] < b[propName])
return -1;
if (a[propName] > b[propName])
return 1;
return 0;
};
}
objs.sort(compare("last_nom"));
C'est un problème simple, je ne sais pas pourquoi les gens ont une solution aussi complexe.
Une fonction de tri simple (basée sur un algorithme tri rapide):
function sortObjectsArray(objectsArray, sortKey)
{
// Quick Sort:
var retVal;
if (1 < objectsArray.length)
{
var pivotIndex = Math.floor((objectsArray.length - 1) / 2); // middle index
var pivotItem = objectsArray[pivotIndex]; // value in the middle index
var less = [], more = [];
objectsArray.splice(pivotIndex, 1); // remove the item in the pivot position
objectsArray.forEach(function(value, index, array)
{
value[sortKey] <= pivotItem[sortKey] ? // compare the 'sortKey' proiperty
less.Push(value) :
more.Push(value) ;
});
retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
}
else
{
retVal = objectsArray;
}
return retVal;
}
Exemple d'utilisation:
var myArr =
[
{ val: 'x', idx: 3 },
{ val: 'y', idx: 2 },
{ val: 'z', idx: 5 },
];
myArr = sortObjectsArray(myArr, 'idx');
En utilisant Ramda,
npm install ramda
import R from 'ramda'
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
var ascendingSortedObjs = R.sortBy(R.prop('last_nom'), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)
Je viens d’améliorer le tri dynamique de Ege Özcan pour plonger au plus profond des objets. Si les données ressemblent à ceci:
obj = [
{
a: { a: 1, b: 2, c: 3 },
b: { a: 4, b: 5, c: 6 }
},
{
a: { a: 3, b: 2, c: 1 },
b: { a: 6, b: 5, c: 4 }
}];
et si vous voulez trier la propriété a.a , je pense que mon amélioration est très utile. J'ajoute de nouvelles fonctionnalités à des objets comme celui-ci:
Object.defineProperty(Object.prototype, 'deepVal', {
enumerable: false,
writable: true,
value: function (propertyChain) {
var levels = propertyChain.split('.');
parent = this;
for (var i = 0; i < levels.length; i++) {
if (!parent[levels[i]])
return undefined;
parent = parent[levels[i]];
}
return parent;
}
});
et modifié _ dynamicSort 's return function:
return function (a,b) {
var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
return result * sortOrder;
}
Et maintenant, vous pouvez trier par a.a. de cette façon:
obj.sortBy('a.a');
Voir le script Commplete dans JSFiddle
Utilisation de xPrototype : https://github.com/reduardo7/xPrototype/blob/master/README.md#sortbycol1-col2-coln
var o = [
{ Name: 'Lazslo', LastName: 'Jamf' },
{ Name: 'Pig', LastName: 'Bodine' },
{ Name: 'Pirate', LastName: 'Prentice' },
{ Name: 'Pag', LastName: 'Bodine' }
];
// Original
o.each(function (a, b) { console.log(a, b); });
/*
0 Object {Name: "Lazslo", LastName: "Jamf"}
1 Object {Name: "Pig", LastName: "Bodine"}
2 Object {Name: "Pirate", LastName: "Prentice"}
3 Object {Name: "Pag", LastName: "Bodine"}
*/
// Sort By LastName ASC, Name ASC
o.sortBy('LastName', 'Name').each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pag", LastName: "Bodine"}
1 Object {Name: "Pig", LastName: "Bodine"}
2 Object {Name: "Lazslo", LastName: "Jamf"}
3 Object {Name: "Pirate", LastName: "Prentice"}
*/
// Sort by LastName ASC and Name ASC
o.sortBy('LastName'.asc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pag", LastName: "Bodine"}
1 Object {Name: "Pig", LastName: "Bodine"}
2 Object {Name: "Lazslo", LastName: "Jamf"}
3 Object {Name: "Pirate", LastName: "Prentice"}
*/
// Sort by LastName DESC and Name DESC
o.sortBy('LastName'.desc, 'Name'.desc).each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pirate", LastName: "Prentice"}
1 Object {Name: "Lazslo", LastName: "Jamf"}
2 Object {Name: "Pig", LastName: "Bodine"}
3 Object {Name: "Pag", LastName: "Bodine"}
*/
// Sort by LastName DESC and Name ASC
o.sortBy('LastName'.desc, 'Name'.asc).each(function(a, b) { console.log(a, b); });
/*
0 Object {Name: "Pirate", LastName: "Prentice"}
1 Object {Name: "Lazslo", LastName: "Jamf"}
2 Object {Name: "Pag", LastName: "Bodine"}
3 Object {Name: "Pig", LastName: "Bodine"}
*/
Voie 1:
Vous pouvez utiliser Underscore.js
. Importez le trait de soulignement en premier.
import * as _ from 'underscore';
let SortedObjs = _.sortBy(objs, 'last_nom');
Voie 2: Utilisez la fonction de comparaison.
function compare(first, second) {
if (first.last_nom < second.last_nom)
return -1;
if (first.last_nom > second.last_nom)
return 1;
return 0;
}
objs.sort(compare);
En utilisant lodash ou Underscore, c'est un morceau de gâteau
> const sortedList = _.orderBy(objs, [last_nom], [asc]); // asc or desc
Ça marche pour moi. Ici, il restera non défini jusqu'à la fin.
function sort(items, property, direction) {
function compare(a, b) {
if(!a[property] && !b[property]) {
return 0;
} else if(a[property] && !b[property]) {
return -1;
} else if(!a[property] && b[property]) {
return 1;
} else {
const value1 = a[property].toString().toUpperCase(); // ignore upper and lowercase
const value2 = b[property].toString().toUpperCase(); // ignore upper and lowercase
if (value1 < value2) {
return direction === 0 ? -1 : 1;
} else if (value1 > value2) {
return direction === 0 ? 1 : -1;
} else {
return 0;
}
}
}
return items.sort(compare);
}
var items = [
{ name: 'Edward', value: 21 },
{ name: 'Sharpe', value: 37 },
{ name: 'And', value: 45 },
{ name: 'The', value: -12 },
{ name: undefined, value: -12 },
{ name: 'Magnetic', value: 13 },
{ name: 'Zeros', value: 37 }
];
console.log('Ascending Order:- ');
console.log(sort(items, 'name', 0));
console.log('Decending Order:- ');
console.log(sort(items, 'name', 1));
Je me suis posé le problème de trier un tableau d'objets, en changeant la priorité des valeurs. En gros, je veux trier un tableau de peuples par leur âge, puis par nom de famille - ou simplement par nom de famille, nom. Je pense que c'est la solution la plus simple comparée à d'autres réponses.
il est utilisé en appelant sortPeoples (['array', 'of', 'properties'], reverse = false)
///////////////////////example array of peoples ///////////////////////
var peoples = [
{name: "Zach", surname: "Emergency", age: 1},
{name: "Nancy", surname: "Nurse", age: 1},
{name: "Ethel", surname: "Emergency", age: 1},
{name: "Nina", surname: "Nurse", age: 42},
{name: "Anthony", surname: "Emergency", age: 42},
{name: "Nina", surname: "Nurse", age: 32},
{name: "Ed", surname: "Emergency", age: 28},
{name: "Peter", surname: "Physician", age: 58},
{name: "Al", surname: "Emergency", age: 58},
{name: "Ruth", surname: "Registration", age: 62},
{name: "Ed", surname: "Emergency", age: 38},
{name: "Tammy", surname: "Triage", age: 29},
{name: "Alan", surname: "Emergency", age: 60},
{name: "Nina", surname: "Nurse", age: 58}
];
//////////////////////// Sorting function /////////////////////
function sortPeoples(propertyArr, reverse) {
function compare(a,b) {
var i=0;
while (propertyArr[i]) {
if (a[propertyArr[i]] < b[propertyArr[i]]) return -1;
if (a[propertyArr[i]] > b[propertyArr[i]]) return 1;
i++;
}
return 0;
}
peoples.sort(compare);
if (reverse){
peoples.reverse();
}
};
////////////////end of sorting method///////////////
function printPeoples(){
$('#output').html('');
peoples.forEach( function(person){
$('#output').append(person.surname+" "+person.name+" "+person.age+"<br>");
} )
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<html>
<body>
<button onclick="sortPeoples(['surname']); printPeoples()">sort by ONLY by surname ASC results in mess with same name cases</button><br>
<button onclick="sortPeoples(['surname', 'name'], true); printPeoples()">sort by surname then name DESC</button><br>
<button onclick="sortPeoples(['age']); printPeoples()">sort by AGE ASC. Same issue as in first case</button><br>
<button onclick="sortPeoples(['age', 'surname']); printPeoples()">sort by AGE and Surname ASC. Adding second field fixed it.</button><br>
<div id="output"></div>
</body>
</html>
// Sort Array of Objects
// Data
var booksArray = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
// Property to Sort By
var args = "last_nom";
// Function to Sort the Data by given Property
function sortByProperty(property) {
return function (a, b) {
var sortStatus = 0,
aProp = a[property].toLowerCase(),
bProp = b[property].toLowerCase();
if (aProp < bProp) {
sortStatus = -1;
} else if (aProp > bProp) {
sortStatus = 1;
}
return sortStatus;
};
}
// Implementation
var sortedArray = booksArray.sort(sortByProperty(args));
console.log("sortedArray: " + JSON.stringify(sortedArray) );
Sortie du journal de la console:
"sortedArray:
[{"first_nom":"Pig","last_nom":"Bodine"},
{"first_nom":"Lazslo","last_nom":"Jamf"},
{"first_nom":"Pirate","last_nom":"Prentice"}]"
Adapté en fonction de cette source: http://www.levihackwith.com/code-snippet-how-to-sort-an-array-of-json-objects-by-property/
Cela triera un tableau imbriqué à deux niveaux en fonction de la propriété qui lui est transmise dans l'ordre alphanumérique.
function sortArrayObjectsByPropAlphaNum(property) {
return function (a,b) {
var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
var aA = a[property].replace(reA, '');
var bA = b[property].replace(reA, '');
if(aA === bA) {
var aN = parseInt(a[property].replace(reN, ''), 10);
var bN = parseInt(b[property].replace(reN, ''), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
return a[property] > b[property] ? 1 : -1;
}
};
}
Usage:
objs.sort(utils.sortArrayObjectsByPropAlphaNum('last_nom'));
Donc, voici un algorithme de tri qui peut trier dans n’importe quel ordre, dans un tableau de tout type d’objets, sans la restriction de la comparaison de types de données (c.-à-d. Nombre, chaîne)
function smoothSort(items,prop,reverse) {
var length = items.length;
for (var i = (length - 1); i >= 0; i--) {
//Number of passes
for (var j = (length - i); j > 0; j--) {
//Compare the adjacent positions
if(reverse){
if (items[j][prop] > items[j - 1][prop]) {
//Swap the numbers
var tmp = items[j];
items[j] = items[j - 1];
items[j - 1] = tmp;
}
}
if(!reverse){
if (items[j][prop] < items[j - 1][prop]) {
//Swap the numbers
var tmp = items[j];
items[j] = items[j - 1];
items[j - 1] = tmp;
}
}
}
}
return items;
}
le premier argument items est le tableau d'objets,
prop est la clé de l'objet sur lequel vous voulez trier,
reverse est un paramètre booléen qui, lorsqu'il est vrai, donne un ordre croissant et faux, il retourne un ordre décroissant.
Je vais vous donner une solution implémentant l'algorithme selectionSort, il est simple et efficace
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
function selection_Sort(num) {
//console.log(num);
var temp, index;
for (var i = 0; i <= num.length - 1; i++) {
index = i;
for (var j = i + 1; j <= num.length - 1; j++) {
// you can use first_nom/last_nom,any way you choose to sort
if (num[j]. last_nom < num[index]. last_nom) {
index = j;
}
}
//below is the swapping part
temp = num[i]. last_nom;
num[i]. last_nom = num[index]. last_nom;
num[index]. last_nom = temp;
};
console.log(num);
return num;
}
selection_Sort(objs);
Grand de voir de telles bonnes réponses
Si vous avez des objets imbriqués
const objs = [{
first_nom: 'Lazslo',
last_nom: 'Jamf',
moreDetails: {
age: 20
}
}, {
first_nom: 'Pig',
last_nom: 'Bodine',
moreDetails: {
age: 21
}
}, {
first_nom: 'Pirate',
last_nom: 'Prentice',
moreDetails: {
age: 22
}
}];
nestedSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
const a = prop2 ? e1[prop1][prop2] : e1[prop1],
b = prop2 ? e2[prop1][prop2] : e2[prop1],
sortOrder = direction === "asc" ? 1 : -1
return (a < b) ? -sortOrder : (a > b) ? sortOrder : 0;
}
et l'appelle comme
objs.sort(nestedSort("last_nom"));
objs.sort(nestedSort("last_nom", null, "desc"));
objs.sort(nestedSort("moreDetails", "age"));
objs.sort(nestedSort("moreDetails", "age", "desc"));
Il est également possible de créer une fonction de tri dynamique lors de la programmation en TypeScript, mais les types deviennent plus compliqués dans ce cas.
function sortByKey<O>(key: keyof O, decending: boolean = false): (a: O, b: O) => number {
const order = decending ? -1 : 1;
return (a, b): number => {
const valA = a[key];
const valB = b[key];
if (valA < valB) {
return -order;
} else if (valA > valB) {
return order;
} else {
return 0;
}
}
}
Ceci peut être utilisé dans TypeScript comme suit:
const test = [
{
id: 0,
},
{
id: 2,
}
]
test.sort(sortByKey('id')) // OK
test.sort(sortByKey('id1')) // ERROR
test.sort(sortByKey('')) // ERROR