Как отсортировать массив объектов с несколькими значениями полей в JavaScript

Я нашел отличный метод для сортировки массива объектов на основе одного из свойств, как определено в:

Сортировка массива объектов по значению свойства строки в JavaScript

Использование этой функции отлично работает для одного сортировки (во всех браузерах) и даже для сортировки в другом классе EXCEPT с помощью Google Chrome! Здесь Ege Özcan отличная процедура сортировки для массивов объектов

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

Использование массива с именем "Данные" (конечно, у моего массива много пар объектов)...

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

Я могу получить правильный вид, где порядок указан как все значения в каждой категории, делая это...

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

Сначала сортируя по Value, а затем по Category, мой массив помещает все значения в порядке сортировки со всеми перечисленными выше значениями бизнес-базы, а затем всеми значениями на основе персонажа. Отлично! За исключением Chrome, где данные сортируются должным образом по категориям, но порядок значений в каждой категории кажется довольно случайным.

Знает ли кто-нибудь лучший способ сделать сортировку в сортировке, которая также будет работать в Chrome?

Ответы

Ответ 1

Я создал многопараметрическую версию этой функции 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;
    }
}

Я создал массив следующим образом:

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

и он работал, когда я это делал,

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

И вот рабочий пример: http://jsfiddle.net/ZXedp/

Ответ 2

Самый простой способ выполнить сортировку нескольких критериев Javascript (или сортировку нескольких параметров) - использовать .sort, объединить несколько параметров вместе и сравнить два укуса.

Например:

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

});

Я включил JsFiddle Script здесь: http://jsfiddle.net/oahxg4u3/6/

Ответ 3

Вы также можете посмотреть на thenBy.js: https://github.com/Teun/thenBy.js

Он позволяет использовать стандартный массив Array.sort, но с использованием метода firstBy(). thenBy(). thenBy().

Ответ 4

Я теперь этот пост довольно старый, так или иначе, я нашел его сегодня и цитируя Ege Özcan, я улучшил его отличное решение, реализующее функциональность DESC-ASC SQL-Like для всех, кого интересует (http://jsfiddle.net/ZXedp/65/):

function dynamicSortMultiple() {
    var props=[];
    /*Let 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)));
    }
}

вызвать функцию следующим образом:

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

Ответ 5

Вот мое решение. Это быстрее, чем lodash _. SortBy() функция сортировки нескольких столбцов примерно в два раза (см. http://jsperf.com/multi-column-sort. Я генерирую текст функции сортировки, а затем использую его в стандартном .sort(). Он также работает в Chrome и Firefox.

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