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

У меня есть массив объектов JavaScript:

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

Как я могу отсортировать их по значению last_nomв JavaScript?

Я знаю о sort(a,b), но это, кажется, работает только над строками и числами. Нужно ли добавлять toString()метод к моим объектам?

15.07.2009 03:17:47
Этот скрипт позволяет вам делать это, если вы не хотите написать свою собственную функцию сравнения или сортировщик: thomasfrank.se/sorting_things.html
Baversjo 15.07.2009 03:31:47
самый быстрый способ - использовать модуль изоморфного массива сортировки, который изначально работает как в браузере, так и в узле, поддерживая любой тип ввода, вычисляемые поля и пользовательские порядки сортировки.
Lloyd 21.10.2019 20:25:02
30 ОТВЕТОВ
РЕШЕНИЕ

Достаточно просто написать собственную функцию сравнения:

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

Или встроенный (с Марко Демайо):

objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0)); 
3873
21.04.2019 14:30:29
Или встроенный: objs.sort (function (a, b) {return (a.last_nom> b.last_nom)? 1: ((b.last_nom> a.last_nom)? -1: 0);});
Marco Demaio 24.02.2010 18:29:10
Официальные документы: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
mikemaccana 18.05.2012 09:11:15
return a.last_nom.localeCompare(b.last_nom)тоже будет работать
Cerbrus 14.02.2013 10:37:20
для тех, кто ищет сортировку, где поле числовое, тело функции сравнения: return a.value - b.value;(ASC)
Andre Figueiredo 8.01.2014 12:06:25
@Cerbrus localeCompareважен при использовании акцентированных символов на иностранных языках, а также более элегантен.
Marcos Lima 1.06.2016 16:38:05

Если у вас есть повторяющиеся фамилии, вы можете отсортировать их по имени-

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;
});
62
29.04.2014 18:35:50
@BadFeelingAboutЭто что означает возврат -1 или 1? Я понимаю, что -1 буквально означает, что A меньше, чем B только по синтаксису, но зачем использовать 1 или -1? Я вижу, что все используют эти числа в качестве возвращаемых значений, но почему? Спасибо.
Chris22 22.08.2018 06:15:00
@ Chris22 возвращенное отрицательное число означает, что bдолжно следовать aза массивом. Если положительное число возвращается, значит, aдолжно прийти после b. Если 0возвращается, значит, они считаются равными. Вы всегда можете прочитать документацию: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
BadFeelingAboutThis 22.08.2018 16:54:52
@BadFeelingAboutЭто спасибо за объяснение и ссылку. Хотите верьте, хотите нет, но я погуглил различные фрагменты кода, используя 1, 0, -1прежде, чем спросил это здесь. Я просто не нашел нужную мне информацию.
Chris22 22.08.2018 17:07:34

Вместо использования пользовательской функции сравнения вы также можете создать тип объекта с помощью пользовательского toString()метода (который вызывается функцией сравнения по умолчанию):

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
15.07.2009 07:21:48

Вы также можете создать динамическую функцию сортировки, которая сортирует объекты по значению, которое вы передаете:

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

Таким образом, вы можете иметь массив таких объектов:

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

... и это будет работать, когда вы делаете:

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

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

Несколько параметров

Вы можете использовать функцию ниже для генерации функций сортировки с несколькими параметрами сортировки.

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

Что позволит вам сделать что-то вроде этого:

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

Массив подклассов

Для тех, кому повезло, кто может использовать ES6, который позволяет расширять нативные объекты:

class MyArray extends Array {
    sortBy(...args) {
        return this.sort(dynamicSortMultiple.apply(null, args));
    }
}

Это позволило бы это:

MyArray.from(People).sortBy("Name", "-Surname");
830
18.05.2019 15:09:53
Обратите внимание, что имена свойств в JavaScript могут быть любой строкой, и если у вас есть свойства, начинающиеся с «-» (крайне маловероятно и, вероятно, не очень хорошая идея), вам нужно изменить функцию dynamicSort, чтобы использовать что-то другое в качестве обратной сортировки показатель.
Ege Özcan 10.01.2013 15:18:39
Я заметил, что dynamicSort()в приведенном выше примере заглавные буквы будут размещаться перед строчными. Например, если у меня есть значения APd, Aklin, и Abe- результаты в ASC - то должно быть Abe, Aklin, APd. Но с вашим примером, результаты APd, Abe, Aklin. В любом случае, чтобы исправить это поведение?
Lloyd Banks 26.07.2017 22:06:50
@LloydBanks, если вы используете это строго для строк, то вы можете использовать var result = a[property].localeCompare(b[property]);вместо var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;.
Ege Özcan 6.08.2017 08:55:17
@ EgeÖzcan Должны быть либо элементы, расположенные сверху или снизу, вот реализация, которую я закончил с использованием pastebin.com/g4dt23jU
dzh 20.01.2018 00:37:17
Это отличное решение, но есть одна проблема, если сравнивать числа. Пожалуйста, добавьте это перед проверкой:if( !isNaN(a[property]) ) a[property] = Number(a[property]); if( !isNaN(b[property]) ) b[property] = Number(b[property]);
Ivijan Stefan Stipić 3.04.2018 05:48:02

underscore.js

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

sortBy_.sortBy (list, iterator, [context]) Возвращает отсортированную копию списка, ранжированного в порядке возрастания по результатам выполнения каждого значения через итератор. Итератор также может быть строковым именем свойства для сортировки (например, длина).

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
10.03.2016 19:34:40
Дэвид, могли бы вы изменить ответ сказать, var sortedObjs = _.sortBy( objs, 'first_nom' );. objsбудет не сортировать себя в результате этого. Функция вернет отсортированный массив. Это сделало бы это более явным.
Jess 9.01.2014 04:01:06
Чтобы изменить сортировку:var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
Erdal G. 31.01.2016 10:43:07
вам нужно загрузить библиотеку javascript "underscore":<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>
and-bri 29.05.2017 18:28:54
Также доступно Lodashдля тех, кто предпочитает это
WoJ 17.04.2018 10:49:32
В lodash это было бы то же самое: var sortedObjs = _.sortBy( objs, 'first_nom' );или, если вы хотите, чтобы это было в другом порядке:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
Travis Heeter 15.11.2018 19:10:03

Простое и быстрое решение этой проблемы с использованием наследования прототипа:

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

Пример / Использование

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

Обновление: больше не изменяет исходный массив.

48
15.05.2015 21:45:09
Это не просто вернуть другой массив. но на самом деле сортирует оригинал!
Vinay Aggarwal 21.07.2012 05:43:29
Если вы хотите убедиться, что вы используете естественную сортировку с числами (то есть 0,1,2,10,11 и т. Д.), Используйте parseInt с набором Radix. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… so: return (parseInt (a [p], 10)> parseInt (b [p], 10))? 1: (parseInt (a [p], 10) <parseInt (b [p], 10))? -1: 0;
Paul 11.05.2015 19:14:21
@codehuntr Спасибо за исправление. но я полагаю, вместо того, чтобы делать функцию сортировки для этой сенсибилизации, лучше, если мы сделаем отдельную функцию для исправления типов данных. Потому что функция сортировки не может сказать, какое свойство будет содержать данные какого типа. :)
Vinay Aggarwal 21.05.2015 16:55:57
Очень хорошо. Переверните стрелки, чтобы получить эффект asc / desc.
Abdul Sadik Yalcin 15.11.2017 15:08:53
никогда, никогда не предлагайте решение, которое модифицирует прототип основного объекта
pbanka 27.10.2018 00:17:12

дополнительные параметры desc для кода 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
16.09.2012 20:22:18

Комбинируя динамическое решение Ege с идеей Vinay, вы получаете хорошее надежное решение:

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

Применение:

// 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
23.04.2013 16:07:34
Спасибо за идею! Кстати, пожалуйста, не поощряйте людей менять прототип массива (см. Предупреждение в конце моего примера).
Ege Özcan 10.05.2013 14:51:08

Возможно, вам придется преобразовать их в нижний регистр, чтобы избежать путаницы.

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
14.08.2013 10:40:10

Не понимаю, почему люди делают это так сложно:

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

Для более строгих двигателей:

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

Поменяйте местами оператор, чтобы отсортировать его в обратном алфавитном порядке.

179
22.04.2014 19:25:59
Это на самом деле не правильно, так как функция, используемая в сортировке, должна возвращать -1, 0 или 1, но вышеприведенная функция возвращает логическое значение. Сортировка отлично работает в Chrome, но не работает, например, в PhantomJS. См. Code.google.com/p/phantomjs/issues/detail?id=1090
schup 22.04.2014 15:05:30
Некоторые двигатели объясняют глупость, этот способ был своего рода эксплуатацией. Я обновил свой ответ правильной версией.
p3lim 22.04.2014 19:23:15
Я бы предложил редактирование, чтобы вынуть первую версию. Он более лаконичен, поэтому выглядит привлекательнее, но он не работает, по крайней мере, ненадежно. Если кто-то пробует его в одном браузере, и он работает, он может даже не осознавать, что у него есть проблема (особенно если он не читал комментарии). Вторая версия работает правильно, поэтому в первой нет необходимости.
Kate 11.03.2016 15:01:39
@Simon Я действительно ценю сначала «слегка неправильную» версию, поскольку более строгая реализация занимает несколько секунд, чтобы разобрать и понять, и было бы намного сложнее без нее.
Aaron Sherman 24.06.2016 16:50:45
@ Lion789 просто сделай это:if(a.count == b.count) return a.name > b.name; else return a.count > b.count;
p3lim 7.05.2017 17:16:53

Пример использования:

objs.sort(sortBy('last_nom'));

Автор сценария:

/**
 * @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;
  };
};
22
21.03.2019 17:18:00
спасибо, что разбили это, я пытаюсь понять, почему цифры 1, 0, -1используются для сортировки. Даже с вашим объяснением выше, которое выглядит очень хорошо - я все еще не совсем понимаю. Я всегда думаю, -1что при использовании свойства длины массива, то есть: arr.length = -1означает, что элемент не найден. Я, наверное, здесь все перемешиваю, но не могли бы вы помочь мне понять, почему цифры 1, 0, -1используются для определения порядка? Спасибо.
Chris22 22.08.2018 06:23:56
Это не совсем точно, но это может помочь думать об этом так: функция, переданная в array.sort, вызывается один раз для каждого элемента в массиве в качестве аргумента с именем «a». Возвращаемое значение каждого вызова функции - это то, как индекс (номер текущей позиции) элемента «a» должен быть изменен по сравнению со следующим элементом «b». Индекс определяет порядок массива (0, 1, 2 и т. Д.). Поэтому, если «а» находится в индексе 5, а вы возвращаете -1, то 5 + -1 == 4 (переместите его ближе к фронту) 5 + 0 == 5 (держать его там, где он есть) и т. д. Он обходит массив, сравнивая 2 соседей каждый раз, пока не достигает конца, оставляя отсортированный массив.
Jamie Mason 23.08.2018 09:09:35
спасибо, что нашли время, чтобы объяснить это дальше. Поэтому, используя ваше объяснение и MDN Array.prototype.sort , я расскажу вам, что я об этом думаю: по сравнению с aи b, если aон больше, чем b1, добавьте к индексу aи поместите его позади b, если aон меньше, чем b, вычтите 1 из aи поместите его перед b. Если aи bсовпадают, добавьте 0 aи оставьте его там, где он есть.
Chris22 23.08.2018 16:28:58

Согласно вашему примеру, вам нужно отсортировать по двум полям (фамилия, имя), а не по одному. Вы можете использовать библиотеку Alasql, чтобы сделать эту сортировку одной строкой:

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

Попробуйте этот пример на jsFiddle .

8
18.12.2014 11:09:04

Использование 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
9.02.2015 20:23:09

Я только что улучшил динамическую сортировку Ege Özcan, чтобы погрузиться глубоко в объекты. Если данные выглядят так:

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

и если вы хотите отсортировать его по аа свойства я думаю , что мое повышение помогает очень хорошо. Я добавляю новую функциональность к таким объектам:

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

и изменил _dynamicSort «s возвращение функции:

return function (a,b) {
        var result = ((a.deepVal(property) > b.deepVal(property)) - (a.deepVal(property) < b.deepVal(property)));
        return result * sortOrder;
    }

И теперь вы можете сортировать аа таким образом:

obj.sortBy('a.a');

Смотрите скрипт Commplete в JSFiddle

5
23.05.2017 12:03:09

Сортировка (более) сложных массивов объектов

Поскольку вы, вероятно, сталкиваетесь с более сложными структурами данных, такими как этот массив, я бы расширил решение.

TL; DR

Более подключаемая версия, основанная на очень милом ответе @ ege-Özcan .

проблема

Я столкнулся с ниже и не мог изменить это. Я также не хотел временно сплющивать объект. Также я не хотел использовать подчеркивание / lodash, в основном из соображений производительности и удовольствия, чтобы реализовать это самостоятельно.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

Цель

Цель состоит в том, чтобы отсортировать его в первую очередь People.Name.nameпоPeople.Name.surname

Препятствия

Теперь в базовом решении используются скобочные обозначения для вычисления свойств для динамической сортировки. Здесь, однако, мы должны были бы также динамически создавать обозначение в скобках, так как можно было бы ожидать, что некоторые сработают, People['Name.name']но это не так.

Простое выполнение People['Name']['name'], с другой стороны, является статичным и позволяет вам только спуститься на n-й уровень.

Решение

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

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

пример

Рабочий пример на JSBin

13
23.05.2017 12:18:33
Почему? Это не ответ на оригинальный вопрос, и «цель» может быть решена просто с помощью People.sort ((a, b) => {return a.Name.name.localeCompare (b.Name.name) || a.Name .surname.localeCompare (b.Name.surname)})
Tero Tolonen 3.05.2016 16:02:05
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
29.10.2015 13:09:48
Пожалуйста, рассмотрите возможность редактирования своего поста, чтобы добавить больше объяснения о том, что делает ваш код и почему это решит проблему. Ответ, который в основном содержит только код (даже если он работает), обычно не помогает ОП понять их проблему.
Drenmi 29.10.2015 18:16:07

Это простая проблема, не знаю, почему у людей такое сложное решение.
Простая функция сортировки (на основе алгоритма быстрой сортировки ):

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

Пример использования:

var myArr = 
        [
            { val: 'x', idx: 3 },
            { val: 'y', idx: 2 },
            { val: 'z', idx: 5 },
        ];
myArr = sortObjectsArray(myArr, 'idx');
6
19.11.2015 14:27:57
Как реализовать быструю сортировку в js - простое решение? Простой алгоритм, но не простое решение.
Andrew 23.11.2015 22:46:09
Это просто, поскольку не использует никаких внешних библиотек и не меняет прототип объекта. На мой взгляд, длина кода не имеет прямого влияния на сложность кода
Gil Epshtain 24.11.2015 12:02:20
Что ж, позвольте мне попробовать с другими словами: как изобретать колесо является простым решением?
Roberto14 9.12.2015 17:36:20

Простой способ:

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

Посмотрите, что '.toLowerCase()'необходимо для предотвращения ошибок при сравнении строк.

10
15.01.2016 13:32:57
Вы можете использовать функции стрелок, чтобы сделать код немного более элегантным:objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
Sertage 24.05.2017 15:04:33
Это неправильно по той же причине, что и здесь .
Patrick Roberts 18.07.2018 09:24:37
Функции стрелок не соответствуют ES5. Тонны двигателей по-прежнему ограничены ES5. В моем случае я нахожу ответ выше значительно лучше, так как я нахожусь на двигателе ES5 (принудительно моей компанией)
dylanh724 21.07.2018 08:50:37

В ES6 / ES2015 или новее вы можете сделать это так:

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

До ES6 / ES2015

objs.sort(function(a, b) {
    return a.last_nom.localeCompare(b.last_nom)
});
394
8.11.2019 17:11:33
это было доступно начиная с JS 1.1, жирная стрелка для этого - ES6 / 2015. Но все же очень полезный и лучший на мой взгляд ответ
Jon Harding 22.02.2016 20:30:59
@PratikKelwalkar: если вам нужно повернуть вспять, просто переключите сравнение a и b: objs.sort ((a, b) => b.last_nom.localeCompare (a.last_nom));
Vlad Bezden 26.05.2016 18:24:21
можно ли использовать индекс , а также для решения поля для сортировки: вместо last_nomиспользования только число в массиве: 1?
and-bri 29.05.2017 18:15:52
@VladBezden спасибо за ваш ответ! Это первое решение с очень небольшим программным усилием и правильными результатами сортировки и строковым массивом, например: ["Name1", "Name10", "Name2", "что-то еще", "Name11"]. У меня есть сортировка для правильной работыobjs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true}));
scipper 9.01.2018 08:49:39
Чтобы сделать это по убыванию чисел: .sort ((a, b) => b.numberProperty - a.numberProperty). По возрастанию: .sort ((a, b) => a.numberProperty - b.numberProperty)
Sebastian Patten 23.05.2019 05:05:58
objs.sort(function(a,b){return b.last_nom>a.last_nom})
8
8.03.2016 09:51:36
На самом деле это не сработало, пришлось использовать принятый ответ. Это не было правильно сортировать.
madprops 21.02.2017 11:15:32

Я столкнулся с проблемой сортировки массива объектов с изменением приоритета значений, в основном я хочу отсортировать массив людей по возрасту, а затем по фамилии - или просто по фамилии, имени. Я думаю, что это самое простое решение по сравнению с другими ответами.

это 'используется вызовом 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
16.03.2016 14:08:31
множество людей s :(
RaisingAgent 14.02.2017 14:17:59

Здесь есть много хороших ответов, но я хотел бы отметить, что они могут быть расширены очень просто для достижения гораздо более сложной сортировки. Единственное, что вам нужно сделать, это использовать оператор OR для цепочки функций сравнения:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Где fn1, fn2... - функции сортировки, которые возвращают [-1,0,1]. Это приводит к «сортировке по fn1», «сортировке по fn2», которая почти равна ORDER BY в SQL.

Это решение основано на поведении ||оператора, который оценивает первое вычисленное выражение, которое может быть преобразовано в true .

Самая простая форма имеет только одну встроенную функцию, например:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

Имея два шага с last_nom, first_nomпорядок сортировки будет выглядеть следующим образом :

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

Универсальная функция сравнения может выглядеть примерно так:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

Эта функция может быть расширена для поддержки числовых полей, чувствительности к регистру, произвольных типов данных и т. Д.

Вы можете использовать их в цепочке по приоритету сортировки:

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

Дело в том, что чистый JavaScript с функциональным подходом может пройти долгий путь без внешних библиотек или сложного кода. Это также очень эффективно, так как не нужно разбирать строки

22
5.05.2016 11:36:14

Еще один вариант:

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

сортирует по возрастанию по умолчанию.

11
26.06.2016 09:10:05
Слегка измененная версия для сортировки по нескольким полям находится здесь при необходимости: stackoverflow.com/questions/6913512/…
Ravshan Samandarov 1.12.2016 12:37:39
// 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) );

Вывод журнала консоли:

"sortedArray: 
[{"first_nom":"Pig","last_nom":"Bodine"},
{"first_nom":"Lazslo","last_nom":"Jamf"},
{"first_nom":"Pirate","last_nom":"Prentice"}]"

Адаптировано на основе этого источника: http://www.levihackwith.com/code-snippet-how-to-sort-an-array-of-json-objects-by-property/

2
9.07.2016 05:45:25

Это отсортирует двухуровневый вложенный массив по переданному ему свойству в алфавитно-цифровом порядке.

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

Применение:

objs.sort(utils.sortArrayObjectsByPropAlphaNum('last_nom'));
2
9.09.2016 01:48:46

Я знаю, что этот вопрос слишком старый, но я не видел ни одной реализации, похожей на мою.
Эта версия основана на идиоме преобразования Шварца .

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

Вот пример, как его использовать:

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
6.11.2016 13:26:18

Итак, вот один алгоритм сортировки, который может сортировать в любом порядке по всему массиву объектов любого типа, без ограничения сравнения типов данных (то есть Number, String).

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;
}
  • первый аргумент items - это массив объектов,

  • prop - это ключ объекта, по которому вы хотите отсортировать,

  • reverse - логический параметр, который в случае истины приводит к возрастанию, а в ложь - в порядке убывания.

2
9.12.2016 14:55:33

Используя Рамду,

нпм установить рамду

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
5.07.2017 07:43:55

Я дам вам решение, реализующее алгоритм selectionSort, оно простое и эффективное

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

Рад видеть такие великолепные ответы

1
16.02.2018 01:42:14

Lodash.js (расширенный набор Underscore.js )

Хорошо не добавлять фреймворк для каждой простой логики, но использование хорошо протестированных утилитных фреймворков может ускорить разработку и уменьшить количество ошибок.

Lodash производит очень чистый код и продвигает более функциональный стиль программирования . Одним взглядом становится ясно, какова цель кода.

Проблема ОП может быть просто решена как:

const sortedObjs = _.sortBy(objs, 'last_nom');

Больше информации? Например, у нас есть следующий вложенный объект:

const users = [
  { 'user': {'name':'fred', 'age': 48}},
  { 'user': {'name':'barney', 'age': 36 }},
  { 'user': {'name':'wilma'}},
  { 'user': {'name':'betty', 'age': 32}}
];

Теперь мы можем использовать сокращение _.property,user.age чтобы указать путь к свойству, которое должно соответствовать. Мы отсортируем пользовательские объекты по вложенному свойству age. Да, это позволяет сопоставлять вложенные свойства!

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

Хотите, чтобы это было наоборот? Нет проблем. Используйте _.reverse .

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

Хотите совместить обе цепочки ?

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

Или когда вы предпочитаете поток по цепочке

const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users); 
26
4.03.2020 09:41:54