Pregunta Clasificar matriz de objetos por valor de propiedad de cadena en JavaScript


Tengo una matriz de objetos de JavaScript:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

¿Cómo puedo ordenarlos por el valor de last_nom en JavaScript?

Se acerca de sort(a,b), pero eso solo parece funcionar en cadenas y números. ¿Debo agregar un método toString a mis objetos?


1815
2017-07-15 03:17


origen


Respuestas:


Es bastante fácil escribir su propia función de comparación:

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

O en línea (c / o Marco Demaio):

objs.sort(function(a,b) {return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0);} ); 

2695
2017-07-15 03:35



También puede crear una función de clasificación dinámica que clasifique los objetos por su valor que pase:

function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

Entonces puedes tener una variedad de objetos como este:

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

... y funcionará cuando lo hagas:

People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));

En realidad, esto ya responde la pregunta. La siguiente parte está escrita porque muchas personas se contactaron conmigo, quejándose de que no funciona con múltiples parámetros.

Múltiples parámetros

Puede usar la función siguiente para generar funciones de clasificación con múltiples parámetros de clasificación.

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

Lo cual te permitiría hacer algo como esto:

People.sort(dynamicSortMultiple("Name", "-Surname"));

Sumarlo al prototipo

(La implementación que está justo debajo está inspirada en Mike Res responder)

No recomendaría cambiar un prototipo de objeto nativo, sino solo dar un ejemplo para que pueda implementarlo en sus propios objetos (Para los entornos que lo admiten, también puede usar Object.defineProperty como se muestra en la siguiente sección, que al menos no tiene el efecto secundario negativo de ser enumerable, como se describe en la última parte)

La implementación del prototipo sería algo como lo siguiente (Aquí hay un ejemplo de trabajo)

//Don't just copy-paste this code. You will break the "for-in" loops
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Array.prototype.sortBy = function() {
        return this.sort(_dynamicSortMultiple.apply(null, arguments));
    }
}();

La forma "correcta" de agregarlo al prototipo

Si se dirige a IE v9.0 y luego, como mencioné anteriormente, use Object.defineProperty Me gusta esto (ejemplo de trabajo)

//Won't work below IE9, but totally safe otherwise
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Object.defineProperty(Array.prototype, "sortBy", {
        enumerable: false,
        writable: true,
        value: function() {
            return this.sort(_dynamicSortMultiple.apply(null, arguments));
        }
    });
}();

Esto puede ser un compromiso aceptable hasta que operador de enlace llega

Toda esa diversión prototipo permite esto:

People.sortBy("Name", "-Surname");

Deberías leer esto

Si usa el método de acceso directo al prototipo (Object.defineProperty está bien) y otro código no verifica hasOwnProperty¡los gatitos mueren! Ok, para ser honesto, ningún gatito tiene ningún daño, pero probablemente las cosas se rompan y cualquier otro desarrollador en tu equipo te odiará:

evil

¿Ves ese último "SortBy"? Sí. No genial. Use Object.defineProperty donde pueda, y deje el Array.prototype solo de lo contrario.


649
2018-01-21 15:03



underscore.js

usa subrayado, es pequeño e impresionante ...

sortBy_.sortBy (list, iterator, [context]) Devuelve una copia ordenada de   lista, clasificada en orden ascendente por los resultados de ejecutar cada valor   a través del iterador. Iterator también puede ser el nombre de la cadena de la propiedad   ordenar por (por ejemplo, longitud).

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

155
2018-05-10 21:24



No entiendo por qué las personas lo hacen tan complicado:

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

Para motores más estrictos:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

Cambie el operador para que se ordene por orden alfabético inverso.


140
2018-01-24 19:35



En ES6 / ES2015 o posterior puede hacerlo de esta manera:

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

136
2018-01-29 19:44



Si tiene apellidos duplicados, puede ordenarlos por nombre.

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

51
2017-07-15 04:03



Solución simple y rápida a este problema usando prototipo de herencia:

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

Ejemplo / Uso

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

Actualizar: Ya no modifica la matriz original.


38
2017-07-10 11:54



En lugar de utilizar una función de comparación personalizada, también puede crear un tipo de objeto con una función personalizada toString() método (que es invocado por la función de comparación predeterminada):

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

23
2017-07-15 07:21