web-dev-qa-db-fra.com

Trier le tableau d'objets par valeur de propriété de chaîne

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?

2408
Tyrone Slothrop

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)); 
3472
Wogan

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 .

Paramètres multiples

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"));

Tableau de sous-classement

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");
776
Ege Özcan

Dans ES6/ES2015 ou version ultérieure, vous pouvez procéder comme suit:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
302
Vlad Bezden

nderscore.js

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' );
178
David Morrow

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.

169
p3lim

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;
});
61
kennebec

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.

42
Vinay Aggarwal

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;
});
31
0leg

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();
28
Christoph

Vous pouvez utiliser

Le moyen le plus simple: Lodash

( 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']);
26
Harshal

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();
22
Nico Van Belle

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) )

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

22
Tero Tolonen

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;
  };
};
20
Jamie Mason

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 :(

18
Damjan Pavlica

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))
17
Patrick Roberts

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'));
15
a8m

Tri (plus) Tableaux complexes d'objets

Étant donné que vous rencontrez probablement des structures de données plus complexes comme ce tableau, j'élargirais la solution.

TL; DR

Sont la version plus pluggable basée sur @ ege-Özcan est très belle réponse .

Problème

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"}
];

Objectif

Le but est de le trier principalement par People.Name.name et ensuite par People.Name.surname

Obstacles

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.

Solution

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

Exemple de travail sur JSBin

14

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.

11
Ravshan Samandarov

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.

10
Caio Ladislau

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");
9
Mike R

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;
    }
}
9
Behnam Yousefi

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
9
Francois Girard
objs.sort(function(a,b){return b.last_nom>a.last_nom})
8
Roshni Bokade

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 .

8
agershun

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

})
7
Burak Keceli

É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.
  • La soustraction fonctionne sur les champs numériques: var age_order = left.age - right.age;
  • Inverser l'ordre inverse, return -last_nom_order || -first_nom_order || -age_order;
7
Bob Stein
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"));
7
Evgenii

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');
6
Gil Epshtain

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)
6
Sridhar Sg

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

5
Morteza Tourani

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"}
*/
4
Eduardo Cuomo

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);
4
Harunur Rashid

En utilisant lodash ou Underscore, c'est un morceau de gâteau

> const sortedList = _.orderBy(objs, [last_nom], [asc]); // asc or desc
3
karthik006

Ç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));
    
    
3
chandan gupta

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>
2
jmwierzbicki
// 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/

2
Luke Schoen

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'));
2
depiction

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.

2
Partha Roy

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

1
sg28

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"));
0
Mas

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
0
Ferrybig