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?

2684
Tyrone Slothrop 15 juil. 2009 à 07:17

30 réponses

Meilleure réponse

Il 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)); 
3814
KostasX 21 avril 2019 à 14:30

Je n'ai pas vu cette approche particulière suggérée, voici donc une méthode de comparaison laconique 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 un fn qui sélectionne la valeur d'un objet à utiliser comme comparaison, et renvoie une fonction qui peut être transmise directement à Array.prototype.sort(). Dans cet exemple, nous utilisons o.last_nom comme valeur de comparaison, donc 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)
}

Pour les comparer.

En se rappelant 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 || possède une fonctionnalité de court-circuit qui est très utile ici. En raison de son fonctionnement, 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 alors nous retournons +1, mais si fa == fb, alors fa < fb et {{X6} } sont false, il renvoie donc +0.

En prime, voici l'équivalent dans ECMAScript 5 sans fonctions fléchées, 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))
20
Patrick Roberts 30 avril 2019 à 07:35

Vous pouvez utiliser

Moyen le plus simple: Lodash

(https://lodash.com/docs/4.17.10#orderBy)

Cette méthode est similaire à _.sortBy, sauf qu'elle permet de spécifier les ordres de tri des itérés à utiliser pour le tri. 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 croissant ordre de tri des valeurs correspondantes.

Arguments

Collection (Array | Object): collection sur laquelle itérer. [iteratees = [_. identity]] (Array [] | Function [] | Object [] | string []): Les itérés à trier. [commandes] (chaîne []): les ordres de tri des itérés.

Retours

(Tableau): renvoie 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 23 août 2018 à 14:39

Selon votre exemple, vous devez trier par deux champs (nom, prénom), plutôt qu'un. Vous pouvez utiliser la bibliothèque Alasql pour effectuer 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 18 déc. 2014 à 11:09

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 l'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 19 nov. 2015 à 14:27

Encore une 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));

Tri croissant par défaut.

11
Ravshan Samandarov 26 juin 2016 à 09:10
objs.sort(function(a,b){return b.last_nom>a.last_nom})
8
Roshni Bokade 8 mars 2016 à 09:51

Je sais que cette question est trop ancienne, mais je n'ai vu aucune implémentation similaire à la mienne.
Cette version est basée sur l 'idiome de transformation 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 6 nov. 2016 à 13:26

Je viens d'améliorer le tri dynamique de Ege Özcan pour plonger profondément à l'intérieur des objets. Si Data ressemble à 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 souhaitez le trier sur 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 changé la fonction return de _dynamicSort :

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 Script Commplete dans JSFiddle

5
Community 23 mai 2017 à 12:03

Vous devrez peut-être les convertir en minuscules afin d'é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 14 août 2013 à 10:40
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 29 oct. 2015 à 13:09

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;
  };
};
21
Jamie Mason 21 mars 2019 à 17:18

À partir de 2018, il existe une solution beaucoup plus courte et élégante. Utilisez simplement. 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;
});
35
0leg 4 juin 2018 à 15:24

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

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

Avant ES6 / ES2015

objs.sort(function(a, b) {
    return a.last_nom.localeCompare(b.last_nom)
});
383
Victor ifeanyi 8 nov. 2019 à 17:11

underscore.js

Utilisez le soulignement, c'est petit et génial ...

sortBy_.sortBy (liste, itérateur, [contexte]) Renvoie une copie triée de la liste, classée par ordre croissant par les résultats de l'exécution de chaque valeur via l'itérateur. Iterator peut également être le nom de chaîne de la propriété à trier (par exemple, la 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' );
186
Bill Sambrone 10 mars 2016 à 19:34

En combinant la solution dynamique d'Ege avec l'idée de Vinay, vous obtenez une belle solution robuste:

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 23 avril 2013 à 16:07

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 trier par ordre alphabétique inverse.

179
p3lim 22 avril 2014 à 19:25

Paramètres de desc supplémentaires pour le code Ege Özcan

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 Shomali 16 sept. 2012 à 20:22

Il y a beaucoup de bonnes réponses ici, mais je voudrais souligner qu'elles peuvent être étendues très simplement pour obtenir un tri beaucoup plus complexe. La seule chose que vous devez faire est d'utiliser l'opérateur OR pour chaîner des 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 renvoient [-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 à la rel première expression évaluée qui peut être convertie en true.

Le formulaire le plus simple n'a qu'une seule fonction intégrée 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 peut ê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 pour les enchaîner par priorité de tri:

// 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 le JavaScript pur avec une approche fonctionnelle peut vous mener loin sans bibliothèques externes ou code complexe. Il est également très efficace, car aucune analyse de chaîne ne doit être effectuée

22
Tero Tolonen 5 mai 2016 à 11:36

Vous pouvez également créer une fonction de tri dynamique qui trie les objets en fonction de leur 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;
    }
}

Vous pouvez donc avoir un tableau d'objets comme celui-ci:

var People = [
    {Name: "Name", Surname: "Surname"},
    {Name:"AAA", Surname:"ZZZ"},
    {Name: "Name", Surname: "AAA"}
];

... et cela fonctionnera lorsque vous:

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 car de nombreuses personnes 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 d'entre 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");
823
Ege Özcan 18 mai 2019 à 15:09

Avec 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 5 juil. 2017 à 07:43

Si vous avez des noms de famille 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
BadFeelingAboutThis 29 avril 2014 à 18:35

Un moyen simple:

objs.sort(function(a,b) {
  return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});

Vérifiez que '.toLowerCase()' est nécessaire pour éviter les erreurs en comparant les chaînes.

10
Caio Ladislau 15 janv. 2016 à 13:32

Lodash.js (surensemble de Underscore.js)

Il est bon de ne pas ajouter de cadre pour chaque élément logique simple, mais s'appuyer sur des cadres d'utilitaires bien testés peut accélérer le développement et réduire la quantité de bogues.

Lodash produit un code très propre et promeut un style de programmation fonctionnelle . En un coup d'œil, il devient clair quelle est l'intention du code.

Le problème de l'OP peut simplement être 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 _.property raccourci user.age pour spécifier le chemin à la propriété qui doit être mise en correspondance. Nous allons trier les objets utilisateur par la propriété d'âge imbriquée. Oui, il permet la correspondance des propriétés imbriquées!

const sortedObjs = _.sortBy(users, ['user.age']);

Vous voulez qu'il soit inversé? Aucun problème. Utilisez _.reverse.

const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));

Vous voulez combiner les deux en utilisant la chaîne?

const { chain } = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();

Ou quand préférez-vous le flux à la chaîne

const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users); 
26
Nico Van Belle 4 mars 2020 à 09:41

Étant donné l'exemple d'origine:

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 universellement pris en charge et renvoie -1,0,1 si a<b , a==b, a>b respectivement.
  • || dans 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;
  • Annuler pour inverser l'ordre, return -last_nom_order || -first_nom_order || -age_order;
7
Bob Stein 24 févr. 2018 à 00:54

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
10
Francois Girard 28 mai 2018 à 19:54

Solution simple et rapide à ce problème en utilisant l'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"}]

Mettre à jour: ne modifie plus la baie d'origine.

48
Web_Designer 15 mai 2015 à 21:45

Au lieu d'utiliser une fonction de comparaison personnalisée, vous pouvez également créer un type d'objet avec la méthode toString() personnalisée (qui est invoqué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();
29
Christoph 15 juil. 2009 à 07:21

Tri (plus) Tableaux complexes d'objets

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

TL; DR

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

Problème

J'ai rencontré ce qui suit et je n'ai pas pu le changer. Je ne voulais pas non plus aplatir temporairement l'objet. Je ne voulais pas non plus utiliser le soulignement / lodash, principalement pour des raisons de performances et pour le plaisir de l'implémenter 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 secondairement par People.Name.surname

Obstacles

Maintenant, dans la solution de base, utilise la notation entre crochets pour calculer les propriétés à trier dynamiquement. Ici, cependant, nous devons également construire dynamiquement la notation des crochets, car vous vous attendez à ce que certains comme People['Name.name'] fonctionnent - ce qui ne fonctionne pas.

Faire simplement People['Name']['name'], en revanche, est statique et vous permet uniquement de descendre au n niveau.

Solution

Le principal ajout ici sera de parcourir l'arborescence des objets et de déterminer la valeur de la dernière feuille, 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
Community 23 mai 2017 à 12:18

Ancienne réponse incorrecte:

arr.sort((a, b) => a.name > b.name)

MISE À JOUR

Du commentaire de Beauchamp:

arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

Format plus lisible:

arr.sort((a, b) => {
  if (a.name < b.name) return -1
  return a.name > b.name ? 1 : 0
})

Sans ternaires imbriqués:

arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))

Explication: Number() convertira true en 1 et false en 0.

27
Damjan Pavlica 24 déc. 2019 à 21:38
1129216