2012-07-07 13 views
9

me encontré con un gran método para ordenar una serie de objetos en función de una de las propiedades como se define en:Cómo ordenar una serie de objetos con múltiples valores de campo en JavaScript

Sort array of objects by string property value in JavaScript

El uso que las obras de funciones perfectamente para un solo tipo (en todos los navegadores), e incluso un tipo en otro tipo ¡EXCEPTO usando Google Chrome! Aquí está una gran rutina de ordenación de Ege Özcan para las matrices de objetos

function dynamicSort(property) { 
    return function (a,b) { 
     return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0; 
    } 
} 

Usando una matriz denominada "Datos" (por supuesto, mi matriz tiene muchos más pares de objetos) ...

var Data = [{Category: "Business", Value: "ABC"},{Category:"Personal", Value:"XYZ"}]; 

puedo conseguir una especie adecuada donde el orden se muestra como todos los valores dentro de cada categoría al hacer esto ...

Data.sort(dynamicSort("Value")); 
Data.sort(dynamicSort("Category")); 

por primera clasificación en Value, y luego por Category, mi matriz pone todos los valores en orden con todos los valores de Base de negocios listados primero y luego todos los valores basados ​​en Personal. ¡Perfecto! Excepto en Chrome, donde los datos están ordenados por categoría, pero el orden de los valores dentro de cada categoría parece bastante aleatorio.

¿Alguien sabe de una mejor manera de hacer un tipo dentro de un género que también funcionaría en Chrome?

+2

clasificación por A y luego la clasificación de forma independiente por _is B no es igual que la clasificación por A ** y ** B_. Si funcionó en algunos navegadores, fue un golpe de suerte. – Alnitak

Respuesta

35

creé una versión multi-parámetro de esa función dynamicSort:

function dynamicSort(property) { 
    return function (obj1,obj2) { 
     return obj1[property] > obj2[property] ? 1 
      : obj1[property] < obj2[property] ? -1 : 0; 
    } 
} 

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

he creado una matriz como sigue:

var arr = [ 
    {a:"a",b:"a",c:"a"}, 
    {a:"b",b:"a",c:"b"}, 
    {a:"b",b:"a",c:"a"}, 
    {a:"b",b:"a",c:"b"}, 
    {a:"b",b:"b",c:"a"}, 
    {a:"b",b:"b",c:"b"}, 
    {a:"b",b:"b",c:"a"}, 
    {a:"b",b:"b",c:"b"}, 
    {a:"b",b:"b",c:"a"}, 
    {a:"b",b:"b",c:"b"}, 
    {a:"b",b:"b",c:"a"}, 
    {a:"c",b:"b",c:"b"}, 
    {a:"c",b:"c",c:"a"} 
]; 

y funcionó cuando lo hice,

arr.sort(dynamicSortMultiple("c","b","a")); 

Y aquí hay un ejemplo de trabajo: http://jsfiddle.net/ZXedp/

+1

esto sí, también con múltiples propiedades: http://stackoverflow.com/questions/1129216/sorting-objects-in-an-array-by-a-field-value-in-javascript/4760279#4760279 –

1

También es posible que desee echar un vistazo a thenBy.js: https://github.com/Teun/thenBy.js

Se le permite utilizar el estándar Array.sort, pero con firstBy() thenBy() estilo thenBy()...

+0

Mejor: 'firstBy = (function() {function tb (y) {var x = this; función f (a, b) {return x (a, b) || y (a, b);} f.thenBy = tb; return f;} return function (f) {f.thenBy = tb; return f;};})(); ' – Bergi

+0

Me interesa saber por qué esto es mejor. ¿Podrías detallar? Tal vez usando una solicitud de extracción? –

+0

1) solo una, función compartida 'thenBy' 2) no innecesaria' secondaryFunction' 3) es más corta 4) es más funcional, la tuya tendría problemas con 'var a = firstBy (x), b = a.thenBy (y), c = a.thenBy (z) 'porque' a' == 'b' ==' c' – Bergi

0

Aquí está mi solución. Es más rápido que _.sortBy de lodash() función de clasificación varias columnas en cerca de dos veces (véase http://jsperf.com/multi-column-sort. genero texto de función de clasificación, a continuación, utilizarlo en .Sort estándar(). Funciona en Chrome y Firefox también.

function multiColumnSort(arr,sf) { 
    var s = ''; 
    sf.forEach(function(f,idx) { 
     s += 'if(arguments[0].'+f+'>arguments[1].'+f+')return 1;'; 
     s += 'else if(arguments[0].'+f+'==arguments[1].'+f+')'; 
     s += (idx < sf.length-1)? '{' : 'return 0'; 
    }); 
    s += Array(sf.length).join('}')+';return -1'; 
    return arr.sort(new Function(s)); 
}; 
5

La forma más fácil de realizar una Javascript Multi-criterio de clasificación (o Multi-Parameter Sort), es el uso de .sort, concatenar los múltiples parámetros juntos, y comparar las dos picaduras.

Por ejemplo:

data.sort(function (a, b) { 

    var aConcat = a["property1"] + a["property2"]; 
    var bConcat = b["property1"] + b["property2"]; 

    if (aConcat > bConcat) { 
    return 1; 
    } else if (aConcat < bConcat) { 
    return -1; 
    } else { 
    return 0; 
    } 

}); 

He incluido un script jsFiddle aquí: http://jsfiddle.net/oahxg4u3/6/

1

ahora este post es bastante antiguo, de todos modos me pareció hoy y citando Ege Özcan, que mejoró su excelente solución implementando la funcionalidad DESC-ASC SQL-Like para cualquier persona interesada (http://jsfiddle.net/ZXedp/65/):

function dynamicSortMultiple() { 
    var props=[]; 
    /*Let's separate property name from ascendant or descendant keyword*/ 
    for(var i=0; i < arguments.length; i++){ 
     var splittedArg=arguments[i].split(/ +/); 
     props[props.length]=[splittedArg[0], (splittedArg[1] ? splittedArg[1].toUpperCase() : "ASC")]; 
    } 
    return function (obj1, obj2) { 
     var i = 0, result = 0, numberOfProperties = props.length ; 
     /*Cycle on values until find a difference!*/ 
     while(result === 0 && i < numberOfProperties) { 
      result = dynamicSort(props[i][0], props[i][1])(obj1, obj2); 
      i++; 
     } 
     return result; 
    } 
} 

/*Base function returning -1,1,0 for custom sorting*/ 
function dynamicSort(property, isAscDesc) { 
    return function (obj1,obj2) { 
     if(isAscDesc==="DESC"){ 
      return ((obj1[property] > obj2[property]) ? (-1) : ((obj1[property] < obj2[property]) ? (1) : (0))); 
     } 
     /*else, if isAscDesc==="ASC"*/ 
     return ((obj1[property] > obj2[property]) ? (1) : ((obj1[property] < obj2[property]) ? (-1) : (0))); 
    } 
} 

activar la función o menos así:

arr.sort(dynamicSortMultiple("c DESC","b Asc","a")); 
Cuestiones relacionadas