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


644

У мене з’явився масив (див. Нижче один об’єкт у масиві), який мені потрібно сортувати за іменем за допомогою JavaScript. Як я можу це зробити?

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

Відповіді:


1065

Припустимо, у вас є масив 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
Friggin awesome ... Я сортую ноделіст за id ... працює як шарм. Thx тонну!
Коді

74
Для тих, хто приходить пізніше, відповідь Mrchief краща, оскільки це нечутливий до випадків.
mlienau

25
@mlienau, я б не назвав це кращим чи гіршим. Це просто інше
RiaD

19
@RiaD досить справедливо. Просто не можна придумати багато випадків сортування предметів в алфавітному порядку, включаючи корпус, де "Зебра" з'являється в списку перед "яблуком", було б дуже корисно.
mlienau

15
Цей код працює лише в англомовних країнах. В інших країнах вам слід використовувати відповідь ovunccetinlocaleCompare .
Спойк

542

Найкоротший можливий код із ES6!

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

Основна підтримка String.prototype.localeCompare () є універсальною!


27
На сьогодні найкраща відповідь, якщо ви живете у 2017 році
nathanbirrell

52
Найкраща відповідь також, якщо ви живете в 2018 році;)
Симоне

49
Напевно, буде найкращою відповіддю і для 2019 року.
Ахмад Малекі

23
2020, можливо? чи нааа?
kspearrin

15
ах людина, в 2030 році земля затоплюється, і це працює тільки в горах.
Starfs

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

Якщо порівнювані рядки містять символи unicode, які ви можете використовувати 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)) // Коротка n солодка версія ES6!
Nachiketha

4
танки бро. у використанні ES6users.sort((a, b) => a.name.localeCompare(b.name))
Mohmmad Ebrahimi Aval

32

Гарний маленький ES6 один вкладиш:

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

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

1
Звичайно, дякую, що помітили це, я додав чек на відповідність значень
Сем Логан

непогано Я думаю, якщо ви дійсно хочете, щоб все це було в одному рядку, вкладені тернарі стають заплутаними для читабельності, хоча
russter

24

Ми можемо використовувати localeCompare, але потрібно перевірити також клавіші на значення фальси

Код нижче не буде працювати, якщо в одному записі відсутнє ім’я.

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

Тому нам потрібно перевірити значення фальси, як показано нижче

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

АБО

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

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

У разі , якщо ми сортуємо імена або що - то зі спеціальними символами, наприклад ñ або AEIOU (Загальними іспанською мовою) , ми могли б використовувати Params локалі ( ес для іспанського в даному випадку) і варіанти , як це:

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

В основному ви можете сортувати масиви методом сортування, але якщо ви хочете сортувати об'єкти, вам доведеться передати функцію сортування методу масиву, тому я наведу вам приклад за допомогою масиву

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 - чи можете ви надати тестові дані (масив користувачів), які показують, що вищевказане рішення дає неправильний результат? (наскільки я знаю, відсутність нуля - це не проблема)
Kamil Kiełczewski

Якщо порівнятиFunction (a, b) повертає 0, залиште a і b незмінними відносно один одного, але відсортованими по відношенню до всіх різних елементів.
Раду Лункасу


@RaduLuncasu нормально, але інформація не означає, що нуль є обов'язковим. Найкращий спосіб показати це - підготувати дані, які не спрацьовують - але, наскільки я знаю, це неможливо - наприклад[9,8,7,6,5,1,2,3].sort((a,b) => a<b ? -1 : 1)
Kamil 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 робиться чотири рази за порівняння, а не два рази.
аменте

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.