Сортировать массив по имени (в алфавитном порядке) в Javascript


647

Я получил массив (см. Ниже для одного объекта в массиве), который мне нужно отсортировать по имени, используя JavaScript. Как мне это сделать?

var user = {
   bio: null,
   email:  "user@domain.com",
   firstname: "Anna",
   id: 318,
   lastAvatar: null,
   lastMessage: null,
   lastname: "Nickson",
   nickname: "anny"
};

Ответы:


1068

Предположим, у вас есть массив users. Вы можете использовать users.sortи передать функцию, которая принимает два аргумента и сравнить их (компаратор)

Должно вернуться

  • что-то отрицательное, если первый аргумент меньше второго (должен быть помещен перед вторым в результирующем массиве)
  • что-то положительное, если первый аргумент больше (должен быть помещен после второго)
  • 0, если эти два элемента равны.

В нашем случае, если два элемента, aи bмы хотим сравнить a.firstnameиb.firstname

Пример:

users.sort(function(a, b){
    if(a.firstname < b.firstname) { return -1; }
    if(a.firstname > b.firstname) { return 1; }
    return 0;
})

Этот код будет работать с любым типом.

Обратите внимание, что в «реальной жизни» ™ вы часто хотите игнорировать регистр, правильно сортировать диакритические знаки, странные символы, такие как ß и т. Д. При сравнении строк, поэтому вы можете захотеть использовать localeCompare. Смотрите другие ответы для ясности.


5
Чертовски здорово ... Я сортирую список узлов по идентификатору ... работает как шарм. Спасибо за тонну!
Коди

74
Для тех, кто придет позже, ответ Мркифа лучше, потому что он не учитывает регистр.
Млиенау

25
@mlienau, я бы не назвал это лучше или хуже. Это просто еще один
RiaD

19
@ RiaD достаточно честно. Просто не могу вспомнить много случаев сортировки элементов по алфавиту, включая регистр, где «Зебра» появляется в списке перед «яблоком», было бы очень полезно.
Млинау,

15
Этот код будет работать только в англоязычных странах. В других странах вы должны использовать ответ ovunccetin сlocaleCompare .
Спойк

546

Кратчайший код с ES6!

users.sort((a, b) => a.firstname.localeCompare(b.firstname))

Базовая поддержка String.prototype.localeCompare () универсальна!


27
Безусловно лучший ответ, если вы живете в 2017 году
nathanbirrell

52
Лучший ответ также, если вы живете в 2018 году;)
Симона

49
Наверное, будет лучшим ответом и для 2019 года.
Ахмад Малеки

24
2020 может быть? или нааа?
kspearrin

15
о человек, в 2030 году земля затопляет, и это работает только в горах.
Звезды

343

Что-то вроде этого:

array.sort(function(a, b){
 var nameA=a.name.toLowerCase(), nameB=b.name.toLowerCase();
 if (nameA < nameB) //sort string ascending
  return -1;
 if (nameA > nameB)
  return 1;
 return 0; //default return value (no sorting)
});

43
Когда сортировка строк очень важна, toLowerCase () - заглавные буквы могут повлиять на ваш вид.
MarzSocks

3
В случае, если кому-то еще интересно, на что влияет toLowerCase, это немного:'a'>'A' //true 'z'>'a' //true 'A'>'z' //false
SimplGy

14
@SimplGy Я бы сказал, что это немного больше, чем вы думаете. Например, как указано в комментариях к принятому ответу, важно знать, будет ли ваша функция сортировки сортировать строку 'Zebra'выше, чем строка 'apple', что она будет делать, если вы не используете .toLowerCase().
PrinceTyke

1
@PrinceTyke, да, это хороший случай. 'Z' < 'a' // trueи'z' < 'a' // false
SimplGy

2
Все действительные точки, и я бы сказал, что сортировка всегда зависит от обстоятельств. Если вы сортируете по именам, чувствительность к регистру может не иметь значения. В других случаях это может. Несмотря на это, я думаю, что адаптироваться к конкретной ситуации несложно, как только вы получите основную идею.
Mrchief

336

Если сравнивать строки содержат символы Юникода вы можете использовать localeCompareфункцию из Stringкласса , как в следующем:

users.sort(function(a,b){
    return a.firstname.localeCompare(b.firstname);
})

3
String.localeCompare не поддерживает Safari и IE <11 :)
CORSAIR

13
@CORSAIR поддерживается, это просто второй и третий параметры, которые не поддерживаются.
Кодлер

6
@CORSAIR использование в примере поддерживается во всех основных браузерах IE: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… . LocaleCompare также учитывает капитализацию, поэтому я думаю, что эта реализация должна считаться лучшей практикой.
Мэтт Дженсен

9
users.sort ((a, b) => a.firstname.localeCompare (b.firstname)) // Короткая и приятная версия ES6!
Начикета

4
танки бро. в ES6 использоватьusers.sort((a, b) => a.name.localeCompare(b.name))
Мохаммад Эбрахими Аваль

32

Милый маленький ES6 один лайнер:

users.sort((a, b) => a.firstname !== b.firstname ? a.firstname < b.firstname ? -1 : 1 : 0);

2
Этот является неполным, так как он не обрабатывает одинаковые значения должным образом.
Карл-Йохан Шегрен

1
Конечно, спасибо, что заметили это, я добавил проверку на соответствие значений
Сэм Логан,

Неплохо, я думаю, если вы действительно хотите, чтобы все это было в одной строке, вложенные троицы путаются из-за читабельности
russter

24

Мы можем использовать localeCompare, но нам также необходимо проверить ключи на наличие значений Falsey

Код ниже не будет работать, если в одной записи отсутствует lname.

obj.sort((a, b) => a.lname.localeCompare(b.lname))

Таким образом, мы должны проверить значение Falsey, как показано ниже

let obj=[
{name:'john',lname:'doe',address:'Alaska'},
{name:'tom',lname:'hopes',address:'California'},
{name:'harry',address:'Texas'}
]
let field='lname';
console.log(obj.sort((a, b) => (a[field] || "").toString().localeCompare((b[field] || "").toString())));

ИЛИ

мы можем использовать lodash, это очень просто. Он обнаружит возвращенные значения, т.е. число или строку, и выполнит сортировку соответственно.

import sortBy from 'lodash/sortBy';
sortBy(obj,'name')

https://lodash.com/docs/4.17.5#sortBy


2
Лодаш довольно опрятен! Не слышал об этом раньше. Работает отлично!
Дерк Ян

15

underscorejs предлагает очень хорошую функцию _.sortBy:

_.sortBy([{a:1},{a:3},{a:2}], "a")

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

_.sortBy([{a:"b"},{a:"c"},{a:"a"}], function(i) {return i.a.toLowerCase()})

2
Второй пример включает в себя возврат строк. sortByОбнаруживает ли возвращаемые значения строки и выполняет ли сортировку по алфавиту? Спасибо
Superjos

12

В случае, если мы сортируем имена или что-то со специальными символами, такими как ñ или áéíóú (обыкновенные по-испански), мы можем использовать параметры params locales ( в данном случае es для испанского языка) и такие параметры :

let user = [{'firstname': 'Az'},{'firstname': 'Áb'},{'firstname':'ay'},{'firstname': 'Ña'},{'firstname': 'Nz'},{'firstname': 'ny'}];


user.sort((a, b) => a.firstname.localeCompare(b.firstname, 'es', {sensitivity: 'base'}))


console.log(user)

Официальные варианты локали можно найти здесь: iana , es (испанский), de (немецкий), fr (французский). О чувствительности базовых средств:

Только строки, отличающиеся базовыми буквами, сравниваются как неравные. Примеры: a ≠ b, a = á, a = A.


8

По сути, вы можете сортировать массивы с помощью метода sort, но если вы хотите отсортировать объекты, вам нужно передать функцию для сортировки метода массива, поэтому я приведу пример использования вашего массива.

user = [{
bio: "<null>",
email: "user@domain.com",
firstname: 'Anna',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
},
{
bio: "<null>",
email: "user@domain.com",
firstname: 'Senad',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
},
{
bio: "<null>",
email: "user@domain.com",
firstname: 'Muhamed',
id: 318,
"last_avatar": "<null>",
"last_message": "<null>",
lastname: 'Nickson',
nickname: 'anny'
}];

var ar = user.sort(function(a, b)
{
  var nA = a.firstname.toLowerCase();
  var nB = b.firstname.toLowerCase();

  if(nA < nB)
    return -1;
  else if(nA > nB)
    return 1;
 return 0;
});

зачем возвращать 0 в конце?
Нобита

=, когда строки одинаковы
Сенад Мешкин

но в этом случае не должны elseбыть удалены? В противном случае это return 0никогда не будет прочитано
Nobita

2
это не «еще», это «еще, если»
Сенад Мешкин


8

Более компактная запись:

user.sort(function(a, b){
    return a.firstname === b.firstname ? 0 : a.firstname < b.firstname ? -1 : 1;
})

это более компактно, но нарушает его контракт: sign(f(a, b)) =-sign(f(b, a))(для a = b)
RiaD

3
возвращение a.firstname == b.firstnameследует использовать ===для полноты
puiu

6

также для сортировки asec и desc, вы можете использовать это: предположим, у нас есть переменная SortType, которая задает сортировку по возрастанию или по убыванию, которую вы хотите:

 users.sort(function(a,b){
            return   sortType==="asc"? a.firstName.localeCompare( b.firstName): -( a.firstName.localeCompare(  b.firstName));
        })

5

Обобщенная функция может быть написана как ниже

    function getSortedData(data, prop, isAsc) {
        return data.sort((a, b) => (a[prop] < b[prop] ? -1 : 1) * (isAsc ? 1 : -1));
   }

Вы можете передать следующие параметры

  1. Данные, которые вы хотите отсортировать
  2. Свойство в данных по нему должно быть отсортировано
  3. Последний параметр имеет логический тип. Он проверяет, хотите ли вы сортировать по возрастанию или по убыванию

4

пытаться

users.sort((a,b)=> (a.firstname>b.firstname)*2-1)


2
функция сортировки должна возвращать -1,0,1. этот возвращает только -1,1.
Раду Лункасу

@RaduLuncasu - можете ли вы предоставить тестовые данные (массив пользователей), которые показывают, что приведенное выше решение дает неправильный результат? (насколько я знаю, пропустить ноль - не проблема)
Камиль Келчевски

Если compareFunction (a, b) возвращает 0, оставьте a и b неизменными по отношению друг к другу, но отсортированные по всем различным элементам.
Раду Лункасу


@RaduLuncasu хорошо, но эта информация не означает, что ноль является обязательным. Лучший способ показать это подготовить данные , которые не работает - но, насколько я знаю , что это невозможно - например[9,8,7,6,5,1,2,3].sort((a,b) => a<b ? -1 : 1)
Камиль Kiełczewski

3

Вы можете использовать это для объектов

transform(array: any[], field: string): any[] {
return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0);}

2

Проще говоря, вы можете использовать этот метод

users.sort(function(a,b){return a.firstname < b.firstname ? -1 : 1});

1

Вы можете использовать метод встроенного массива - sort. Этот метод принимает метод обратного вызова в качестве параметра



    // custom sort function to be passed as param/callback to the Array's sort method
    function myCustomSort(a, b) {
        return (a.toLowerCase() > b.toLowerCase()) ? 1 : -1;
    }

    // Actual method to be called by entity that needs sorting feature
    function sortStrings() {
        var op = Array.prototype.sort.call(arguments, myCustomSort);
    }

    // Testing the implementation
    var sortedArray = sortStrings("Burger", "Mayo1", "Pizza", "boxes", "Apples", "Mayo");
    console.log(sortedArray); //["Apples", "boxes", "Burger", "Mayo", "Mayo1", "Pizza"]


Ключевые моменты, которые следует отметить для понимания этого кода.

  1. Пользовательский метод, в данном случае, myCustomSort должен возвращать +1 или -1 для каждой пары элементов (из входного массива) сравнения.
  2. Используйте toLowerCase()/ toUpperCase()в пользовательском методе обратного вызова сортировки, чтобы различие в регистре не влияло на правильность процесса сортировки.

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

Ура!


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

это также не приносит ничего нового в таблицу, по сравнению с любым из ответов, которые были там с ~ 2011 года.
amenthes

1

Поместил верхние ответы в прототип для сортировки по ключу.

Array.prototype.alphaSortByKey= function (key) {
    this.sort(function (a, b) {
        if (a[key] < b[key])
            return -1;
        if (a[key] > b[key])
            return 1;
        return 0;
    });
    return this;
};

0

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

users.sort(function(a, b){

  //compare two values
  if(a.firstname.toLowerCase() < b.firstname.toLowerCase()) return -1;
  if(a.firstname.toLowerCase() > b.firstname.toLowerCase()) return 1;
  return 0;

})

7
Тот же ответ, что и у Mrchief. Еще одним недостатком является то, что toLowerCase выполняется четыре раза за сравнение, а не два раза.
amenthes

0

Моя реализация прекрасно работает в старых версиях ES:

sortObject = function(data) {
    var keys = Object.keys(data);
    var result = {};

    keys.sort();

    for(var i = 0; i < keys.length; i++) {
        var key = keys[i];

        result[key] = data[key];
    }

    return result;
};

0

Просто для записи, если вы хотите иметь именованную функцию сортировки, синтаксис выглядит следующим образом:

let sortFunction = (a, b) => {
 if(a.firstname < b.firstname) { return -1; }
 if(a.firstname > b.firstname) { return 1; }
 return 0;
})
users.sort(sortFunction)

Обратите внимание, что следующее не работает:

users.sort(sortFunction(a,b))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.