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

avatar
Tyrone Slothrop
15 июля 2009 в 03:17
2043411
55
3337

У меня есть массив объектов 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()?

Источник
Baversjo
15 июля 2009 в 03:31
7

Этот сценарий позволяет вам делать именно это, если вы не хотите написать свою собственную функцию сравнения или сортировщик: thomasfrank.se/sorting_things.html

Lloyd
21 октября 2019 в 20:25
0

Самый быстрый способ - использовать изоморфный модуль sort-array, который изначально работает как в браузере, так и в узле, поддерживая любой тип ввода, вычисляемые поля и настраиваемые порядки сортировки.

artem
28 апреля 2021 в 05:14
2

Пожалуйста, objs.sort((a, b) => a.last_nom > b.last_nom && 1 || -1)

Ali NajafZadeh
3 августа 2021 в 16:56
0

функция 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 (сравнить);

Ali NajafZadeh
3 августа 2021 в 16:56
0

objs.sort ((a, b) => (a.last_nom> b.last_nom)? 1: ((b.last_nom> a.last_nom)? -1: 0))

Ответы (55)

avatar
Wogan
15 июля 2009 в 03:35
4683

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

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))
Marco Demaio
24 февраля 2010 в 18:29
512

Или встроенный: objs.sort (function (a, b) {return (a.last_nom> b.last_nom)? 1: ((b.last_nom> a.last_nom)? -1: 0);});

mikemaccana
18 мая 2012 в 09:11
39

Официальные документы: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…

Cerbrus
14 февраля 2013 в 10:37
226

return a.last_nom.localeCompare(b.last_nom) тоже подойдет.

Andre Figueiredo
8 января 2014 в 12:06
170

для тех, кто ищет сортировку с числовым полем, тело функции сравнения: return a.value - b.value; (ASC)

artem
28 апреля 2021 в 05:12
0

Пожалуйста, напишите короткий код objs.sort((a, b) => a.last_nom > b.last_nom && 1 || -1)

avatar
ccpizza
24 февраля 2022 в 19:00
2

объекты сортировки с Intl.Collator для конкретного случая, когда вы хотите <природного > сортировочных (т.е. 1,2,10,11,111).

const files = [
 {name: "1.mp3", size: 123},
 {name: "10.mp3", size: 456},
 {name: "100.mp3", size: 789},
 {name: "11.mp3", size: 123},
 {name: "111.mp3", size: 456},
 {name: "2.mp3", size: 789},
];

const naturalCollator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});

files.sort((a, b) => naturalCollator.compare(a.name, b.name));

console.log(files);

Поддержка браузера для Intl.Collator

David Scott Kirby
3 марта 2022 в 14:20
0

Это аккуратный подход.

avatar
Rustam
15 января 2022 в 13:14
0

Я знаю, что уже есть много ответов, в том числе с localeCompare, но если вы по какой-то причине не хотите/не можете использовать localeCompare, я бы предложил вам использовать это решение вместо решения с троичным оператором:

objects.sort((a, b) => (a.name > b.name) - (a.name < b.name));

Кто-то может сказать, что не очевидно, что делает этот код, но, на мой взгляд, тернарный оператор хуже. Если один тернарный оператор достаточно читабелен, то два тернарных оператора, встроенных один в другой, — действительно трудно читаемы и уродливы. Однострочный код с двумя операторами сравнения и одним минусом очень прост для чтения и, следовательно, для понимания.

avatar
muasif80
15 июня 2021 в 19:15
16

С учетом регистра

arr.sort((a, b) => a.name > b.name ? 1 : -1);

Нечувствительность к регистру

arr.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1);

Примечание

Если порядок не изменится (в случае тех же строк), условие > завершится ошибкой и будет возвращено -1. Но если строки одинаковы, то возврат 1 или -1 приведет к правильному выводу

Другой вариант - использовать оператор >= вместо >

avatar
Force Bolt
29 мая 2021 в 15:01
1
//Try this way


let objs = [ 
        { first_nom: 'Lazslo', last_nom: 'Jamf'     },
        { first_nom: 'Pig',    last_nom: 'Bodine'   },
        { first_nom: 'Pirate', last_nom: 'Prentice' }
    ];
    const compareBylastNom = (a, b) => {
        // converting to uppercase to have case-insensitive comparison
        const name1 = a.last_nom.toUpperCase();
        const name2 = b.last_nom.toUpperCase();
    
        let comparison = 0;
    
        if (name1 > name2) {
            comparison = 1;
        } else if (name1 < name2) {
            comparison = -1;
        }
        return comparison;
    }
    console.log(objs.sort(compareBylastNom));
avatar
artem
9 апреля 2021 в 12:58
9

Почему бы вам не написать короткий код?

objs.sort((a, b) => a.last_nom > b.last_nom && 1 || -1)
Someone Special
15 апреля 2021 в 09:36
0

что если значения равны? учитывая, что есть 3 значения, которые вы можете вернуть - 1, -1, 0

artem
15 апреля 2021 в 11:15
0

@SomeoneSpecial ну и что? Результат будет тот же

Kaleem Elahi
26 июня 2021 в 17:53
0

Что значит 1 || -1 значит?

avatar
Wallace Sidhrée
19 марта 2021 в 09:54
0

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

  • Передайте имя ключа для сортировки по
  • Выберите тип сортировки: по возрастанию или по убыванию

sortArrayOfObjsByKeyUtil.js

// Sort array of objects by key
// ------------------------------------------------------------
const sortArrayOfObjsByKey = (array, key, ascdesc) =>
  array.sort((a, b) => {
    const x = a[key];
    const y = b[key];
    if (ascdesc === 'asc') {
      return x < y ? -1 : x > y ? 1 : 0;
    }
    if (ascdesc === 'desc') {
      return x > y ? -1 : x < y ? 1 : 0;
    }
    return null;
  });

sortArrayOfObjsByKeyUtil.test.js

import sortArrayOfObjsByKey from './sortArrayOfObjsByKeyUtil';

const unsortedArray = [
  {
    _id: '3df55221-ce5c-4147-8e14-32effede6133',
    title: 'Netlife Design',
    address: {
      PostalAddress: {
        streetAddress: 'Youngstorget 3',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0181',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.914322, lng: 10.749272 },
  },
  {
    _id: 'cd00459f-3755-49f1-8847-66591ef935b2',
    title: 'Home',
    address: {
      PostalAddress: {
        streetAddress: 'Stockfleths gate 58A',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0461',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.937316, lng: 10.751862 },
  },
];

const sortedArray = [
  {
    _id: 'cd00459f-3755-49f1-8847-66591ef935b2',
    title: 'Home',
    address: {
      PostalAddress: {
        streetAddress: 'Stockfleths gate 58A',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0461',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.937316, lng: 10.751862 },
  },
  {
    _id: '3df55221-ce5c-4147-8e14-32effede6133',
    title: 'Netlife Design',
    address: {
      PostalAddress: {
        streetAddress: 'Youngstorget 3',
        addressLocality: 'Oslo',
        addressRegion: null,
        postalCode: '0181',
        addressCountry: 'Norway',
      },
    },
    geopoint: { lat: 59.914322, lng: 10.749272 },
  },
];

describe('sortArrayOfObjsByKey', () => {
  it(`sort array by 'title' key, ascending`, () => {
    const testInput = sortArrayOfObjsByKey(unsortedArray, 'title', 'asc');
    const testOutput = sortedArray;
    expect(testInput).toEqual(testOutput);
  });
});

avatar
Satish Chandra Gupta
3 февраля 2021 в 08:13
2

Метод sort можно изменить для сортировки чего угодно, например массива чисел, строк и даже объектов, используя функцию сравнения.

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

Функция сравнения принимает 2 аргумента, которые обычно называются a и b . На основе этих двух аргументов вы можете изменить метод сортировки, чтобы он работал так, как хотите. если:

  1. Если функция сравнения возвращает меньше 0, то метод sort () сортирует a по более низкому индексу, чем b . Просто a будет перед b.
  2. Если функция сравнения возвращает значение 0, то метод sort () оставляет позиции элементов такими, какие они есть.
  3. Если функция сравнения возвращает больше 0, тогда метод sort () сортирует a с индексом больше, чем b . Просто a появится после b .

Ссылка: Понимание массива сортировки чисел, строк и объектов

Используйте описанную выше концепцию для применения к своему объекту, где a будет свойством вашего объекта.

var objs = [
  { first_nom: 'Lazslo', last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine' },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];
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);
console.log(objs)
// for better look use console.table(objs)
enter image description here
avatar
Marinos An
27 января 2021 в 21:28
1

Для fp-holics:

const objectSorter = (p)=>(a,b)=>((a,b)=>a>b?1:a<b?-1:0)(a[p], b[p]);
objs.sort(objectSorter('first_nom'));

avatar
SeyyedKhandon
4 декабря 2020 в 09:05
4

Простой ответ:

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

Детали :

Сегодня это очень просто. Вы можете сравнивать строки с localeCompare. Как говорится в Mozilla Doc:

Метод localeCompare() возвращает число, указывающее, Ссылочная строка идет before, или after, или is the same as the given string in sort order.

    //example1:
    console.log("aaa".localeCompare("aab")); //-1
    console.log("aaa".localeCompare("aaa")); //0
    console.log("aab".localeCompare("aaa")); //1

    //example2:
    const a = 'réservé'; // with accents, lowercase
    const b = 'RESERVE'; // no accents, uppercase

    console.log(a.localeCompare(b));
    // expected output: 1
    console.log(a.localeCompare(b, 'en', { sensitivity: 'base' }));
    // expected output: 0

Дополнительные сведения см. В документе Mozilla localeCompare:

avatar
Kamil Kiełczewski
10 июня 2020 в 18:04
2

глубокий

На основе этого отличного руководства, я хотел бы разработать ответ Влада Бездена и объяснить, почему localeCompare лучше, чем стандартный метод сравнения, такой как strA > strB. Давайте запустим этот пример

console.log( 'Österreich' > 'Zealand' );  // We expect false
console.log( 'a' > 'Z' );                 // We expect false

Причина в том, что в JS все строки кодируются с использованием UTF-16 и

let str = '';

// order of characters in JS
for (let i = 65; i <= 220; i++) {
  str += String.fromCodePoint(i); // code to character
}

console.log(str);

Сначала идут заглавные буквы (с маленькими кодами), затем маленькие буквы, а затем - символ Ö (после z). Это причина, по которой мы получаем истину в первом фрагменте - потому что оператор > сравнивает коды символов.

Как видите, сравнение символов на разных языках - нетривиальная задача, но, к счастью, современные браузеры поддерживают стандарт интернационализации ECMA-402. Итак, в JS у нас есть strA.localeCompare(strB), который выполняет задание (-1 означает, что strA меньше, чем strB; 1 означает противоположное; 0 означает равно)

console.log( 'Österreich'.localeCompare('Zealand') ); // We expect -1
console.log( 'a'.localeCompare('Z') );                // We expect -1

Хочу добавить, что localeCompare поддерживает два параметра: язык и дополнительные правила

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

objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom,'en',{sensitivity:'case'}))

console.log(objs);

// in '>' comparison 'Jamf' will NOT be next to 'jamf'
avatar
Nur
8 апреля 2020 в 20:29
8

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

Array.prototype.order = function (prop, methods = {}) {
    if (prop?.constructor == Object) {
        methods = prop;
        prop = null;
    }
    const [orderType_a, orderType_b] = methods.reverse ? [1, -1] : [-1, 1];

    const $ = x => prop
        ? methods.insensitive
            ? String(x[prop]).toLowerCase()
            : x[prop]
        : methods.insensitive
            ? String(x).toLowerCase()
            : x;

    const fn = (a, b) => $(a) < $(b) ? orderType_a : $(b) < $(a) ? orderType_b : 0;
    return this.sort(fn);
};

Его можно использовать для сортировки как массива , так и объекта в массиве
.

let items = [{ x: "Z" }, 3, "1", "0", 2, { x: "a" }, { x: 0 }];
items
    .order("x", { insensitive: 1 })
    // [ { x: 0 }, { x: 'a' }, 3, '1', '0', 2, { x: 'Z' } ]
    .order({ reverse: 1 })
    // [ { x: 0 }, { x: 'a' }, 3, 2, { x: 'Z' }, '1', '0' ]
    .sort(x => typeof x == "string" || typeof x == "number" ? -1 : 0)
    // [ '0', '1', 2, 3, { x: 0 }, { x: 'a' }, { x: 'Z' } ]

1-й (необязательно) > для сортировки объектов, содержащихся в массиве.
2-й метод > { reverse: any, insensitive: any }

avatar
Abhishek
3 марта 2020 в 08:50
26

Попробуйте это,

UPTO ES5

//Ascending Sort
items.sort(function (a, b) {
   return a.value - b.value;
});


//Descending Sort
items.sort(function (a, b) {
   return b.value - a.value;
});


IN ES6 & above:

// Ascending sort
items.sort((a, b) => a.value - b.value);

// Descending Sort
 items.sort((a, b) => b.value - a.value);
Omar Hasan
16 марта 2020 в 09:21
1

лучшее и простое решение

avatar
cbdeveloper
20 декабря 2019 в 09:49
10

Вот мой взгляд на это:

Параметр order является необязательным и по умолчанию имеет значение «ASC» для возрастания.

Работает с акцентированными символами и нечувствителен к регистру .

ПРИМЕЧАНИЕ: Он сортирует и возвращает массив ORIGINAL .

function sanitizeToSort(str) {
  return str
    .normalize('NFD')                   // REMOVE ACCENTED AND DIACRITICS
    .replace(/[\u0300-\u036f]/g,'')     // REMOVE ACCENTED AND DIACRITICS
    .toLowerCase()                      // SORT WILL BE CASE INSENSITIVE
  ;
}

function sortByProperty(arr, property, order="ASC") {
  arr.forEach((item) => item.tempProp = sanitizeToSort(item[property]));
  arr.sort((a,b) => order === "ASC" ?
      a.tempProp > b.tempProp ?  1 : a.tempProp < b.tempProp ? -1 : 0
    : a.tempProp > b.tempProp ? -1 : a.tempProp < b.tempProp ?  1 : 0
  );
  arr.forEach((item) => delete item.tempProp);
  return arr;
}

SNIPPET

function sanitizeToSort(str) {
  return str
    .normalize('NFD')                   // REMOVE ACCENTED CHARS
    .replace(/[\u0300-\u036f]/g,'')     // REMOVE DIACRITICS
    .toLowerCase()
  ;
}

function sortByProperty(arr, property, order="ASC") {
  arr.forEach((item) => item.tempProp = sanitizeToSort(item[property]));
  arr.sort((a,b) => order === "ASC" ?
      a.tempProp > b.tempProp ?  1 : a.tempProp < b.tempProp ? -1 : 0
    : a.tempProp > b.tempProp ? -1 : a.tempProp < b.tempProp ?  1 : 0
  );
  arr.forEach((item) => delete item.tempProp);
  return arr;
}

const rockStars = [
  { name: "Axl",
    lastname: "Rose" },
  { name: "Elthon",
    lastname: "John" },
  { name: "Paul",
    lastname: "McCartney" },
  { name: "Lou",
    lastname: "Reed" },
  { name: "freddie",             // WORKS ON LOWER/UPPER CASE
    lastname: "mercury" },
  { name: "Ámy",                 // WORKS ON ACCENTED CHARS TOO
    lastname: "winehouse"}
  
];

sortByProperty(rockStars,"name");

console.log("Ordered by name A-Z:");
rockStars.forEach((item) => console.log(item.name + " " + item.lastname));

sortByProperty(rockStars,"lastname","DESC");

console.log("\nOrdered by lastname Z-A:");
rockStars.forEach((item) => console.log(item.lastname + ", " + item.name));
Ankesh Pandey
27 августа 2020 в 14:37
0

не работает, если список содержит имя в сочетании символа верхнего и нижнего регистра

cbdeveloper
7 сентября 2020 в 08:10
0

@AnkeshPandey Спасибо, что указали на это. Я исправил это.

avatar
SwiftNinjaPro
25 ноября 2019 в 02:03
2

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

function sortObjects(list, orderBy){
    list.sort(function(a, b){
        let byIndex = 0;
        let order = orderBy[byIndex];
        while(!a[order.by] || !b[order.by] || a[order.by] === b[order.by]){
            byIndex++;
            if(byIndex >= orderBy.length){break;}
            order = orderBy[byIndex];
        }
        if(!a[order.by] || !b[order.by] || a[order.by] === b[order.by]){
            return false;
        }
        if(order.desc){
            return a[order.by] < b[order.by];
        }
        return a[order.by] > b[order.by];
    });
    return list;
}

использование:

var objs = [
    {a: 10, b: 20, c: 30},
    {a: 30, b: 10, c: 20},
    {a: 20, b: 10, c: 30},
];

sortObjectList(objs, [{by: 'a'}]);
[
    {a: 10, b: 20, c: 30},
    {a: 20, b: 10, c: 30},
    {a: 30, b: 10, c: 20},
]

sortObjectList(objs, [{by: 'a', desc: true}]);
[
    {a: 30, b: 10, c: 20},
    {a: 20, b: 10, c: 30},
    {a: 10, b: 20, c: 30},
]

sortObjectList(objs, [{by: 'b', desc: true}, {by: 'c'}]);
[
    {a: 10, b: 20, c: 30},
    {a: 30, b: 10, c: 20},
    {a: 20, b: 10, c: 30},
]

другой пример:

var objs = [
    {a: 5, b: 5},
    {a: 10, b: 15},
    {a: 15, b: 25},
    {b: 10},
    {b: 20},
    {a: 10, b: 30},
    {a: 10, b: 12},
];

sortObjectList(objs, [{by: 'a'}, {by: 'b'}]);
[
    {a: 5, b: 5},
    {b: 10},
    {a: 10, b: 12},
    {a: 10, b: 15},
    {b: 20},
    {a: 10, b: 30},
    {a: 15, b: 25},
]
avatar
Jadli
19 ноября 2019 в 11:15
3

эту функцию сортировки можно использовать для сортировки всех объектов,

  • объект

  • deepObject

  • числовой массив

вы также можете выполнить сортировку по сортировке или по убыванию, передав 1, -1 в качестве параметра

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


function dynamicSortAll(property,sortOrders=1) {

/**default sorting will be ascending order if you need descending order
sording you have to pass -1 as param**/

    var sortOrder = sortOrders;
   
    return function (a,b) {

		 var result =(property? ((a.deepVal(property) > b.deepVal(property)) ? 1 : (a.deepVal(property) < b.deepVal(property)) ? -1 : 0) :((a > b) ? 1 : (a < b) ? -1 : 0))
		
        return result * sortOrder;
		
   
    }
}

deepObj = [
    {
        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 }
}];

let deepobjResult=deepObj.sort(dynamicSortAll('a.a',1))
console.log('deepobjResult :'+ JSON.stringify(deepobjResult))
var obj = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];
let objResult=obj.sort(dynamicSortAll('last_nom',1))
console.log('objResult :'+ JSON.stringify(objResult))

var numericObj=[1,2,3,4,5,6]

let numResult=numericObj.sort(dynamicSortAll(null,-1))
console.log('numResult :'+ JSON.stringify(numResult))

let stringSortResult='helloworld'.split('').sort(dynamicSortAll(null,1))

 console.log('stringSortResult:'+ JSON.stringify(stringSortResult))

let uniqueStringOrger=[...new Set(stringSortResult)]; 
 console.log('uniqueStringOrger:'+ JSON.stringify(uniqueStringOrger))
avatar
Ferrybig
7 мая 2019 в 13:38
3

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

function sortByKey<O>(key: keyof O, decending: boolean = false): (a: O, b: O) => number {
    const order = decending ? -1 : 1;
    return (a, b): number => {
        const valA = a[key];
        const valB = b[key];
        if (valA < valB) {
            return -order;
        } else if (valA > valB) {
            return order;
        } else {
            return 0;
        }
    }
}

Это можно использовать в TypeScript следующим образом:

const test = [
    {
        id: 0,
    },
    {
        id: 2,
    }
]

test.sort(sortByKey('id')) // OK
test.sort(sortByKey('id1')) // ERROR
test.sort(sortByKey('')) // ERROR
avatar
Mas
16 марта 2019 в 18:12
1

Если у вас есть вложенные объекты

const objs = [{
        first_nom: 'Lazslo',
        last_nom: 'Jamf',
        moreDetails: {
            age: 20
        }
    }, {
        first_nom: 'Pig',
        last_nom: 'Bodine',
        moreDetails: {
            age: 21
        }
    }, {
        first_nom: 'Pirate',
        last_nom: 'Prentice',
        moreDetails: {
            age: 22
        }
    }];

nestedSort = (prop1, prop2 = null, direction = 'asc') => (e1, e2) => {
        const a = prop2 ? e1[prop1][prop2] : e1[prop1],
            b = prop2 ? e2[prop1][prop2] : e2[prop1],
            sortOrder = direction === "asc" ? 1 : -1
        return (a < b) ? -sortOrder : (a > b) ? sortOrder : 0;
    }

и назовите его как

objs.sort(nestedSort("last_nom"));
objs.sort(nestedSort("last_nom", null, "desc"));
objs.sort(nestedSort("moreDetails", "age"));
objs.sort(nestedSort("moreDetails", "age", "desc"));
avatar
Harshal Y.
23 августа 2018 в 14:39
33

Вы можете использовать Самый простой способ: Lodash

(https://lodash.com/docs/4.17.10#orderBy)

Этот метод похож на _.sortBy, за исключением того, что он позволяет указать порядок сортировки итераций для сортировки. Если заказы не указаны, все значения сортируются в порядке возрастания. В противном случае укажите порядок «по убыванию» для сортировки по убыванию или «по возрастанию» для соответствующих значений.

Аргументы

коллекция (массив | объект): коллекция для перебора. [iteratees = [_. identity]] (Array [] | Function [] | Object [] | string []): итерации для сортировки. [orders] (string []): порядок сортировки итераций.

Возврат

(массив): возвращает новый отсортированный массив.


var _ = require('lodash');
var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];
    
_.orderBy(homes, ['city', 'state', 'zip'], ['asc', 'desc', 'asc']);
avatar
Patrick Roberts
18 июля 2018 в 09:53
35

Я не видел, чтобы предлагался этот конкретный подход, поэтому вот краткий метод сравнения, который мне нравится использовать, который работает как для типов string, так и для number:

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

const sortBy = fn => {
  const cmp = (a, b) => -(a < b) || +(a > b);
  return (a, b) => cmp(fn(a), fn(b));
};

const getLastName = o => o.last_nom;
const sortByLastName = sortBy(getLastName);

objs.sort(sortByLastName);
console.log(objs.map(getLastName));

Объяснение sortBy()

sortBy() принимает fn, который выбирает значение из объекта для использования в сравнении, и возвращает функцию, которую можно передать в Array.prototype.sort(). В этом примере мы сравниваем o.last_nom. Когда мы получаем два объекта, например

a = { first_nom: 'Lazslo', last_nom: 'Jamf' }
b = { first_nom: 'Pig', last_nom: 'Bodine' }

мы сравниваем их с (a, b) => cmp(fn(a), fn(b)). Учитывая, что

fn = o => o.last_nom

мы можем расширить функцию сравнения до (a, b) => cmp(a.last_nom, b.last_nom). Поскольку логическое ИЛИ (||) работает в JavaScript, cmp(a.last_nom, b.last_nom) эквивалентно

if (a.last_nom < b.last_nom) return -1;
if (a.last_nom > b.last_nom) return 1;
return 0;

Между прочим, на других языках это называется оператором трехстороннего сравнения "космический корабль" (<=>).

Наконец, вот синтаксис, совместимый с ES5, без использования стрелочных функций:

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

function sortBy(fn) {
  function cmp(a, b) { return -(a < b) || +(a > b); }
  return function (a, b) { return cmp(fn(a), fn(b)); };
}

function getLastName(o) { return o.last_nom; }
var sortByLastName = sortBy(getLastName);

objs.sort(sortByLastName);
console.log(objs.map(getLastName));
MSOACC
9 июля 2020 в 11:02
0

Мне нравится этот подход, но я считаю, что использование сокращения -(fa < fb) || +(fa > fb) здесь является ошибкой. Это несколько операторов, сжатых в одну строку кода. Альтернатива, написанная с помощью оператора if, была бы гораздо более удобочитаемой, но при этом довольно краткой. Я считаю ошибкой жертвовать удобочитаемостью ради красивости.

Patrick Roberts
9 июля 2020 в 14:55
0

@MSOACC спасибо за ваше мнение, но я с уважением не согласен. Другие языки реализуют трехсторонний оператор сравнения, который выполняет такое же сравнение, поэтому просто представьте его концептуально как fa <=> fb.

rjanjic
9 октября 2020 в 13:48
0

Привет, Патрик, мне нравится ваш ответ, но он будет правильно работать только с английскими символами (const cmp = (a, b) => -(a < b) || +(a > b);). Подумайте о ["ä", "a", "c", "b"].sort(cmp) => ["a", "b", "c", "ä"], где ä доведен до конца. Вместо этого вам, вероятно, следует обновить функцию сравнения до: const cmp = (a, b) => a.localeCompare(b); => ["a", "ä", "b", "c"] Ура и спасибо за ответ ;-)

Patrick Roberts
9 октября 2020 в 19:22
0

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

avatar
chandan gupta
5 июля 2018 в 11:14
5

У меня работает. Здесь он сохранит undefined до конца.

 function sort(items, property, direction) {

    function compare(a, b) {
      if(!a[property] && !b[property]) {
        return 0;
      } else if(a[property] && !b[property]) {
        return -1;
      } else if(!a[property] && b[property]) {
        return 1;
      } else {
        const value1 = a[property].toString().toUpperCase(); // ignore upper and lowercase
        const value2 = b[property].toString().toUpperCase(); // ignore upper and lowercase
        if (value1 < value2) {
          return direction === 0 ? -1 : 1;
        } else if (value1 > value2) {
          return direction === 0 ? 1 : -1;
        } else {
          return 0;
        }
        
      }
    }
    
    return items.sort(compare);
   } 
   
   var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: undefined, value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];
   console.log('Ascending Order:- ');
   console.log(sort(items, 'name', 0));
   console.log('Decending Order:- ');
   console.log(sort(items, 'name', 1));
    
    
avatar
0leg
4 июня 2018 в 15:24
55

По состоянию на 2018 год существует гораздо более короткое и элегантное решение. Просто используйте. Array.prototype.sort ().

Пример:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});
smcstewart
18 июня 2018 в 10:02
10

В вопросе для сравнения использовались строки, а не числа. Ваш ответ отлично подходит для сортировки по числам, но не так хорош для сравнения по строкам.

0leg
26 марта 2019 в 09:10
0

a.value - b.value, используемый для сравнения атрибутов объекта ( числа в данном случае), может быть адаптирован для различных периодов времени данных. Например, регулярное выражение можно использовать для сравнения каждой пары соседних строк .

Bob Stein
28 марта 2019 в 11:30
1

@ 0leg Я хотел бы увидеть здесь пример использования регулярного выражения для подобного сравнения строк.

surendrapanday
10 декабря 2019 в 08:29
0

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

avatar
Harunur Rashid
30 мая 2018 в 09:21
6

Способ 1:

Вы можете использовать Underscore.js. Сначала импортируйте подчеркивание.

 import * as _ from 'underscore';
 let SortedObjs = _.sortBy(objs, 'last_nom');

Способ 2: использовать функцию сравнения.

function compare(first, second) {
     if (first.last_nom < second.last_nom)
         return -1;
     if (first.last_nom > second.last_nom)
       return 1;
    return 0;
 }

objs.sort(compare);
avatar
Francois Girard
28 мая 2018 в 19:54
11

Простая функция, сортирующая массив объектов по свойству

function sortArray(array, property, direction) {
    direction = direction || 1;
    array.sort(function compare(a, b) {
        let comparison = 0;
        if (a[property] > b[property]) {
            comparison = 1 * direction;
        } else if (a[property] < b[property]) {
            comparison = -1 * direction;
        }
        return comparison;
    });
    return array; // Chainable
}

Использование:

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

sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc
manjuvreddy
23 марта 2020 в 17:23
0

Это решение отлично сработало для меня при двунаправленной сортировке. Спасибо

avatar
karthik006
26 марта 2018 в 05:40
4

Используя lodash или Underscore, это проще простого

> const sortedList = _.orderBy(objs, [last_nom], [asc]); // asc or desc
avatar
Bob Stein
24 февраля 2018 в 00:54
8

В исходном примере:

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

Сортировать по нескольким полям:

objs.sort(function(left, right) {
    var last_nom_order = left.last_nom.localeCompare(right.last_nom);
    var first_nom_order = left.first_nom.localeCompare(right.first_nom);
    return last_nom_order || first_nom_order;
});

Примечания

  • a.localeCompare(b) является универсально поддерживаемым и возвращает -1,0,1, если a<b, a==b, a>b соответственно.
  • || в последней строке дает last_nom приоритет над first_nom.
  • Вычитание работает с числовыми полями: var age_order = left.age - right.age;
  • Отменить в обратном порядке, return -last_nom_order || -first_nom_order || -age_order;
avatar
Damjan Pavlica
20 октября 2017 в 12:10
54

Старый неправильный ответ:

arr.sort((a, b) => a.name > b.name)

ОБНОВЛЕНИЕ

Из комментария Бошампа:

arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

Более читаемый формат:

arr.sort((a, b) => {
  if (a.name < b.name) return -1
  return a.name > b.name ? 1 : 0
})

Без вложенных троек:

arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))

Объяснение: Number() приведёт true к 1 и false к 0.

TitanFighter
3 февраля 2018 в 19:55
1

Работает, но результат почему-то нестабильный

Patrick Roberts
18 июля 2018 в 09:23
1

@ AO17 нет, не будет. Вы не можете вычитать строки.

Jean-François Beauchamp
29 августа 2018 в 15:33
16

Это должно сделать это: arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

Ahsan
22 января 2019 в 13:49
3

@ Jean-FrançoisBeauchamp, ваше решение работает отлично и намного лучше.

Kojo
15 января 2020 в 16:43
0

третий с Number простой и приятный!

muasif80
15 июня 2021 в 19:08
2

Почему arr.sort((a, b) => a.name > b.name ? 1 : -1 не работает? Для строк я проверил, что это отлично работает. Если вы хотите нечувствительность к регистру, используйте a.name.toLowerCase() и b.name.toLowerCase()

Damjan Pavlica
15 июня 2021 в 20:21
0

@ muasif80 ваша версия возвращает числа, так что она работает. моя первоначальная версия возвращает логические значения.

avatar
Nico Van Belle
30 августа 2017 в 14:15
39

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

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

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

Проблема с OP может быть решена просто следующим образом:

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); 
avatar
sg28
27 августа 2017 в 10:26
1

Я дам вам решение, реализующее алгоритм 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);

Приятно видеть такие отличные ответы

avatar
Sridhar Sg
5 июля 2017 в 07:43
8

Используя Ramda,

npm install ramda

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)
avatar
Partha Roy
9 декабря 2016 в 14:55
2

Итак, вот один алгоритм сортировки, который может сортировать в любом порядке, по всему массиву любых объектов, без ограничения сравнения типов данных (например, 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 - это логический параметр, который, если он верен в порядке возрастания, а в ложном - в порядке убывания.

avatar
a8m
6 ноября 2016 в 13:18
23

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

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: 'Mashraki',          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'));
avatar
depiction
9 сентября 2016 в 01:48
2

Это позволит отсортировать двухуровневый вложенный массив по переданному ему свойству в буквенно-числовом порядке.

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'));
avatar
Luke Schoen
9 июля 2016 в 05:38
2
// 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/

avatar
ravshansbox
26 июня 2016 в 09:10
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));

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

ravshansbox
1 декабря 2016 в 12:37
1

Слегка измененная версия для сортировки по нескольким полям при необходимости находится здесь: coderhelper.com/questions/6913512/…

Den Kerny
23 мая 2020 в 04:29
0

похоже, это может быть следующая: функция экспорта generateSortFn (prop: string, reverse: boolean = false): (... args: any) => number {return (a, b) => {return a [prop ] <b [опора]? задний ход ? 1: -1: a [опора]> b [опора]? задний ход ? -1: 1: 0; }; }

Den Kerny
25 мая 2020 в 02:00
0

согласен, но в некоторых случаях мне не нужно смотреть на служебные функции.

avatar
Tero Tolonen
5 мая 2016 в 11:36
28

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

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

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

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

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

// 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 с функциональным подходом может пройти долгий путь без внешних библиотек или сложного кода. Это также очень эффективно, поскольку не нужно выполнять синтаксический анализ строк

avatar
jmwierzbicki
16 марта 2016 в 14:01
2

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

используется при вызове 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>
Penguin9
14 февраля 2017 в 14:17
3

массив людей s :(

avatar
Roshni Bokade
8 марта 2016 в 09:51
11

Предупреждение !
Использование этого решения не рекомендуется , поскольку оно не приводит к сортировке массива. Он оставлен здесь для использования в будущем, потому что идея не редкость.

objs.sort(function(a,b){return b.last_nom>a.last_nom})
madprops
21 февраля 2017 в 11:15
2

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

avatar
Vlad Bezden
29 января 2016 в 19:44
654

В 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)
});
Jon Harding
22 февраля 2016 в 20:30
36

это было доступно с JS 1.1, жирная стрелка к этому - ES6 / 2015. Но все же очень полезно и, на мой взгляд, лучший ответ

Vlad Bezden
26 мая 2016 в 18:24
17

@PratikKelwalkar: если вам нужно поменять местами, просто переключите сравнение a и b: objs.sort ((a, b) => b.last_nom.localeCompare (a.last_nom));

avatar
Caio Ladislau
15 января 2016 в 13:32
12

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

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

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

Sertage
24 мая 2017 в 15:04
4

Вы можете использовать стрелочные функции, чтобы код стал немного более элегантным: objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );

Patrick Roberts
18 июля 2018 в 09:24
0

Это неверно по той же причине, что объясняется здесь.

dylanh724
21 июля 2018 в 08:50
2

Стрелочные функции не подходят для ES5. Тонны двигателей по-прежнему ограничены ES5. В моем случае я считаю, что приведенный выше ответ значительно лучше, так как я использую движок ES5 (по принуждению моей компании)

avatar
Gil Epshtain
19 ноября 2015 в 14:27
7

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

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');
Andrew
23 ноября 2015 в 22:46
5

Как реализация быстрой сортировки в js - простое решение? Простой алгоритм, но не простое решение.

Gil Epshtain
24 ноября 2015 в 12:02
0

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

Roberto14
9 декабря 2015 в 17:36
2

Что ж, позвольте мне попробовать другие слова: как изобретать колесо - простое решение?

avatar
Evgenii
29 октября 2015 в 13:09
8
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"));
Drenmi
29 октября 2015 в 18:16
1

Пожалуйста, подумайте о редактировании вашего сообщения, чтобы добавить больше объяснений о том, что делает ваш код и почему он решает проблему. Ответ, который в основном просто содержит код (даже если он работает), обычно не помогает OP понять их проблему.

avatar
eljefedelrodeodeljefe
10 августа 2015 в 15:52
16

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

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

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://coderhelper.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

Tero Tolonen
3 мая 2016 в 16:02
3

Почему? Это не ответ на исходный вопрос, и «цель» может быть решена просто с помощью People.sort ((a, b) => {return a.Name.name.localeCompare (b.Name.name) || a.Name .surname.localeCompare (b.Name.surname)})

avatar
Morteza Tourani
29 июня 2015 в 01:10
5

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

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

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

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 return :

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

avatar
Eduardo Cuomo
9 февраля 2015 в 20:23
4

Используя xPrototype :

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"}
*/

avatar
agershun
18 декабря 2014 в 11:09
8

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

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

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

avatar
Jamie Mason
30 апреля 2014 в 10:02
26

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

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;
  };
};
Chris22
22 августа 2018 в 06:23
0

спасибо за разбивку, я пытаюсь понять, почему цифры 1, 0, -1 используются для сортировки. Даже с учетом вашего объяснения выше, которое выглядит очень хорошо - я все еще не совсем понимаю его. Я всегда думаю о -1 как об использовании свойства длины массива, то есть: arr.length = -1 означает, что элемент не найден. Я, наверное, тут все путаю, но не могли бы вы помочь мне понять, почему цифры 1, 0, -1 используются для определения порядка? Спасибо.

Jamie Mason
23 августа 2018 в 09:09
1

Это не полностью , но может помочь думать об этом так: функция, переданная в array.sort, вызывается один раз для каждого элемента в массиве в качестве аргумента с именем «a». Возвращаемое значение каждого вызова функции - это то, как следует изменить индекс (номер текущей позиции) элемента «a» по сравнению со следующим элементом «b». Индекс определяет порядок массива (0, 1, 2 и т. Д.). Итак, если «a» находится в индексе 5 и вы возвращаете -1, то 5 + -1 == 4 (переместите его ближе к переднему краю) 5 + 0 == 5 (держите его там, где он есть) и т. д. Он проходит по массиву, сравнивая 2 соседа каждый раз, пока не достигнет конца, оставляя отсортированный массив.

Chris22
23 августа 2018 в 16:28
0

спасибо, что нашли время, чтобы объяснить это дальше. Итак, используя ваше объяснение и MDN Array.prototype.sort, я скажу вам, что я думаю об этом: по сравнению с a и b, если a больше, чем b прибавьте 1 к индексу a и поместите его после b, если a меньше, чем b, вычтите 1 из a и поместите его перед b. Если a и b совпадают, добавьте 0 к a и оставьте его на месте.

avatar
Burak Keceli
14 августа 2013 в 10:40
7

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

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

})
avatar
Mike R
23 апреля 2013 в 16:07
10

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

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");
Ege Özcan
10 мая 2013 в 14:51
1

Спасибо за идею! Кстати, не поощряйте людей изменять прототип массива (см. Предупреждение в конце моего примера).

avatar
Behnam Shomali
16 сентября 2012 в 20:22
10

дополнительные параметры описания для кода 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;
    }
}
avatar
Vinay Aggarwal
10 июля 2012 в 11:54
58

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

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

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

Vinay Aggarwal
21 июля 2012 в 05:43
7

Он не просто возвращает другой массив. но на самом деле сортирует исходный !.

Paul
11 мая 2015 в 19:14
0

Если вы хотите убедиться, что используете естественную сортировку с числами (например, 0,1,2,10,11 и т. Д.), Используйте parseInt с набором Radix. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… итак: return (parseInt (a [p], 10)> parseInt (b [p], 10))? 1: (parseInt (a [p], 10) <parseInt (b [p], 10))? -1: 0;

Vinay Aggarwal
21 мая 2015 в 16:55
0

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

Abdul Sadik Yalcin
15 ноября 2017 в 15:08
0

Очень хорошо. Переверните стрелки, чтобы получить эффект asc / desc.

pbanka
27 октября 2018 в 00:17
7

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

avatar
David Morrow
10 мая 2012 в 21:24
210

underscore.js

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

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

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' );
Jess
9 января 2014 в 04:01
20

Дэвид, не могли бы вы отредактировать ответ, чтобы он сказал: var sortedObjs = _.sortBy( objs, 'first_nom' );. В результате objs не будет отсортирован сам. Функция вернет отсортированный массив. Это сделало бы его более ясным.

Erdal G.
31 января 2016 в 10:43
11

Для обратной сортировки: var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();

and-bri
29 мая 2017 в 18:28
2

вам необходимо загрузить библиотеку javascript «подчеркивание»: <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>

WoJ
17 апреля 2018 в 10:49
6

Также доступен в Lodash для тех, кто предпочитает этот

Travis Heeter
15 ноября 2018 в 19:10
4

В lodash это будет то же самое: var sortedObjs = _.sortBy( objs, 'first_nom' ); или, если вы хотите, в другом порядке: var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );

avatar
Ege Özcan
21 января 2011 в 15:03
948

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

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(...args));
    }
}

Это позволит:

MyArray.from(People).sortBy("Name", "-Surname");
Inigo
7 июля 2021 в 02:30
1

Хороший. Теперь существует версия этого ответа на Typescript: coderhelper.com/a/68279093/8910547. Оставайся (тип) в безопасности! 😉

avatar
Christoph
15 июля 2009 в 07:21
33

Вместо использования настраиваемой функции сравнения вы также можете создать тип объекта с помощью настраиваемого метода 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();
avatar
kennebec
15 июля 2009 в 04:03
77

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

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;
});
Chris22
22 августа 2018 в 06:15
0

@BadFeelingAboutThis что означает возврат -1 или 1? Я понимаю, что -1 буквально означает, что A меньше B только по синтаксису, но зачем использовать 1 или -1? Я вижу, что все используют эти числа как возвращаемые значения, но почему? Спасибо.

BadFeelingAboutThis
22 августа 2018 в 16:54
1

@ Chris22 возвращенное отрицательное число означает, что b должен стоять после a в массиве. Если возвращается положительное число, это означает, что a должен стоять после b. Если возвращается 0, это означает, что они считаются равными. Вы всегда можете прочитать документацию: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

Chris22
22 августа 2018 в 17:07
0

@BadFeelingAbout Это спасибо, за объяснение и ссылку. Вы не поверите, но я искал в Google различные фрагменты кода, используя 1, 0, -1, прежде чем спросил об этом здесь. Я просто не нашел нужной информации.