Сортировать массив объектов по значению свойства строки
У меня есть массив объектов 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()
метод для моих объектов?
62 ответа
Достаточно просто написать собственную функцию сравнения:
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));
Вы также можете создать динамическую функцию сортировки, которая сортирует объекты по значению, которое вы передаете:
function dynamicSort(property) {
var sortOrder = 1;
if(property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a,b) {
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"));
Добавление его в прототип
(Реализация, которая чуть ниже вдохновлена ответом Mike R)
Я бы не рекомендовал менять собственный прототип объекта, а просто привести пример, чтобы вы могли реализовать его на своих собственных объектах (Для сред, которые его поддерживают, вы также можете использовать Object.defineProperty, как показано в следующем разделе, который по крайней мере не имеет отрицательного побочного эффекта перечисления, как описано в последней части)
Реализация прототипа будет выглядеть примерно так ( вот рабочий пример):
//Don't just copy-paste this code. You will break the "for-in" loops
!function() {
function _dynamicSortMultiple(attr) {
/* dynamicSortMultiple function body comes here */
}
function _dynamicSort(property) {
/* dynamicSort function body comes here */
}
Array.prototype.sortBy = function() {
return this.sort(_dynamicSortMultiple.apply(null, arguments));
}
}();
"ОК" способ добавить его к прототипу
Если вы ориентируетесь на IE v9.0 и выше, то, как я уже упоминал, используйте Object.defineProperty следующим образом ( рабочий пример):
//Won't work below IE9, but totally safe otherwise
!function() {
function _dynamicSortMultiple(attr) {
/* dynamicSortMultiple function body comes here */
}
function _dynamicSort(property) {
/* dynamicSort function body comes here */
}
Object.defineProperty(Array.prototype, "sortBy", {
enumerable: false,
writable: true,
value: function() {
return this.sort(_dynamicSortMultiple.apply(null, arguments));
}
});
}();
Это может быть приемлемым компромиссом, пока не прибудет оператор связывания.
Все эти прототипы веселья позволяют это:
People.sortBy("Name", "-Surname");
Вы должны прочитать это
Если вы используете метод прямого доступа к прототипу (Object.defineProperty в порядке), а другой код не проверяет hasOwnProperty, котята умирают! Ладно, если честно, ни один котенок не причинит никакого вреда, но, вероятно, что-то сломается, и любой другой разработчик в вашей команде будет вас ненавидеть
Видите этот последний "SortBy"? Да уж. Не круто. Используйте Object.defineProperty, где вы можете, и оставьте Array.prototype один, в противном случае.
В ES6/ES2015 или новее вы можете сделать это так:
objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));
используйте подчеркивание, его маленький и удивительный...
sortBy_.sortBy (list, iterator, [context]) Возвращает отсортированную копию списка, ранжированного в порядке возрастания по результатам выполнения каждого значения через итератор. Итератор также может быть строковым именем свойства для сортировки (например, длина).
var objs = [
{ first_nom: 'Lazslo',last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
var sortedObjs = _.sortBy( objs, 'first_nom' );
Не понимаю, почему люди делают это так сложно:
objs.sort(function(a, b){
return a.last_nom > b.last_nom;
});
Для более строгих двигателей:
objs.sort(function(a, b){
return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});
Поменяйте местами оператор, чтобы отсортировать его в обратном алфавитном порядке.
С учетом регистра
arr.sort((a, b) => a.name > b.name ? 1 : -1);
Без учета регистра
arr.sort((a, b) => a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1);
Если нет изменений в порядке тех же строк, возвращается
-1
не будет иметь никакого эффекта, или вы можете использовать
>=
оператор
Если у вас есть повторяющиеся фамилии, вы можете отсортировать их по имени-
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;
});
По состоянию на 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;
});
Простое и быстрое решение этой проблемы с использованием наследования прототипа:
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"}]
Обновление: больше не изменяет исходный массив.
У меня есть кусок кода, который работает для меня:
arr.sort((a, b) => a.name > b.name)
ОБНОВЛЕНИЕ: не работает всегда, поэтому это не правильно:(
Lodash.js (расширенный набор http://underscorejs.org/)
Хорошо не добавлять фреймворк для каждой простой логики, но полагаться на хорошо протестированные сервисные фреймворки, ускорить разработку и уменьшить количество написанных ошибок - не стыдно.
Lodash производит очень чистый код и продвигает более функциональный стиль программирования, что приводит к меньшему количеству ошибок. Одним взглядом становится ясно, каково намерение, если код.
Проблема ОП может быть просто решена как:
const sortedObjs = _.sortBy(objs, 'last_nom');
Больше информации? Например, у нас есть следующий вложенный объект:
const users = [
{ 'user': {'name':'fred', 'age': 48}},
{ 'user': {'name':'barney', 'age': 36 }},
{ 'user': {'name':'wilma'}},
{ 'user': {'name':'betty', 'age': 32}}
];
Теперь мы можем использовать сокращение _.property user.age
указать путь к свойству, которое должно быть сопоставлено. Мы отсортируем пользовательские объекты по вложенному свойству age. Да, он позволяет сопоставлять вложенные свойства!
const sortedObjs = _.sortBy(users, ['user.age']);
Хотите, чтобы это было наоборот? Нет проблем. Используйте _.reverse.
const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));
Хотите объединить оба с помощью цепочки вместо?
const sortedObjs = _.chain(users).sortBy('user.age').reverse().value();
Ты можешь использовать
Самый простой способ: Lodash
( https://lodash.com/docs/4.17.10#orderBy)
Этот метод похож на _.sortBy, за исключением того, что он позволяет указывать порядок сортировки итерируемых для сортировки. Если заказы не указаны, все значения сортируются в порядке возрастания. В противном случае укажите порядок "desc" для убывающего или "asc" для возрастающего порядка сортировки соответствующих значений.
аргументы
collection (Array|Object): коллекция для повторения. [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']);
Я не видел, чтобы этот конкретный подход предлагал, так что вот краткий метод сравнения, который мне нравится использовать, который работает для обоих 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 => (a, b) => -(fn(a) < fn(b)) || +(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
в качестве значения для сравнения, поэтому всякий раз, когда мы получаем два объекта через Array.prototype.sort()
такие как
{ first_nom: 'Lazslo', last_nom: 'Jamf' }
а также
{ first_nom: 'Pig', last_nom: 'Bodine' }
мы используем
(a, b) => -(fn(a) < fn(b)) || +(fn(a) > fn(b))
сравнить их.
Вспоминая это fn = o => o.last_nom
мы можем расширить функцию сравнения до эквивалентной
(a, b) => -(a.last_nom < b.last_nom) || +(a.last_nom > b.last_nom)
Логическое ИЛИ ||
Оператор имеет функцию короткого замыкания, которая очень полезна здесь. Из-за того, как это работает, тело функции выше означает
if (a.last_nom < b.last_nom) return -1
return +(a.last_nom > b.last_nom)
Так что если a < b
мы возвращаемся -1
иначе если a > b
тогда мы вернемся +1
, но если a == b
, затем a < b
а также a > b
ложны, поэтому он возвращает +0
,
В качестве дополнительного бонуса, вот эквивалент в ECMAScript 5.1 без функций стрелок, что, к сожалению, не так кратко:
var objs = [
{ first_nom: 'Lazslo', last_nom: 'Jamf' },
{ first_nom: 'Pig', last_nom: 'Bodine' },
{ first_nom: 'Pirate', last_nom: 'Prentice' }
];
var sortBy = function (fn) {
return function (a, b) {
return -(fn(a) < fn(b)) || +(fn(a) > fn(b))
}
}
var getLastName = function (o) { return o.last_nom }
var sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
Вместо использования пользовательской функции сравнения вы также можете создать тип объекта с пользовательским 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();
Здесь есть много хороших ответов, но я хотел бы отметить, что они могут быть расширены очень просто для достижения гораздо более сложной сортировки. Единственное, что вам нужно сделать, это использовать оператор OR для цепочки функций сравнения:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
куда fn1
, fn2
,... - это функции сортировки, которые возвращают [-1,0,1]. Это приводит к "сортировке по fn1", "сортировке по fn2", которая в значительной степени равна ORDER BY в SQL.
Это решение основано на поведении ||
оператор, который оценивает первое вычисленное выражение, которое может быть преобразовано в true.
Самая простая форма имеет только одну встроенную функцию, например:
// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )
Имея два шага с last_nom
,first_nom
порядок сортировки будет выглядеть так:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) ||
a.first_nom.localeCompare(b.first_nom) )
Универсальная функция сравнения может выглядеть примерно так:
// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])
Эта функция может быть расширена для поддержки числовых полей, чувствительности к регистру, произвольных типов данных и т. Д.
Вы можете использовать их в цепочке по приоритету сортировки:
// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
Дело в том, что чистый JavaScript с функциональным подходом может пройти долгий путь без внешних библиотек или сложного кода. Это также очень эффективно, так как не нужно разбирать строки
Попробуй это,
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);
Метод sort можно изменить для сортировки чего угодно, например массива чисел, строк и даже объектов, используя функцию сравнения.
Функция сравнения передается как необязательный аргумент методу сортировки.
Функция сравнения принимает 2 аргумента, которые обычно называются a и b. На основе этих двух аргументов вы можете изменить метод сортировки, чтобы он работал так, как хотите. если:
- Если функция сравнения возвращает меньше 0, тогда метод sort () сортирует a с индексом ниже, чем b. Просто a будет перед b.
- Если функция сравнения возвращает значение 0, то метод sort () оставляет позиции элементов как есть.
- Если функция сравнения возвращает больше 0, тогда метод sort () сортирует a по индексу, большему, чем b. Просто a будет после b.
Ссылка: Общие сведения о сортировочном массиве чисел, строк и объектов
Использование выше концепции для применения на вашем объекте , где будет вам свойство объекта.
Пример использования:
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}
*/
function 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.
var 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.
var moveLarger = reverse ? -1 : 1;
/**
* @param {*} a
* @param {*} b
* @return {Number}
*/
return function(a, b) {
if (a[key] < b[key]) {
return moveSmaller;
}
if (a[key] > b[key]) {
return moveLarger;
}
return 0;
};
}
Почему бы тебе не написать короткий код?
objs.sort((a, b) => a.last_nom > b.last_nom && 1 || -1)
Я знаю, что этот вопрос слишком старый, но я не видел ни одной реализации, похожей на мою.
Эта версия основана на идиоме преобразования Шварца.
function sortByAttribute(array, ...attrs) {
// generate an array of predicate-objects contains
// property getter, and descending indicator
let predicates = attrs.map(pred => {
let descending = pred.charAt(0) === '-' ? -1 : 1;
pred = pred.replace(/^-/, '');
return {
getter: o => o[pred],
descend: descending
};
});
// schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
return array.map(item => {
return {
src: item,
compareValues: predicates.map(predicate => predicate.getter(item))
};
})
.sort((o1, o2) => {
let i = -1, result = 0;
while (++i < predicates.length) {
if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
if (result *= predicates[i].descend) break;
}
return result;
})
.map(item => item.src);
}
Вот пример, как его использовать:
let games = [
{ name: 'Pako', rating: 4.21 },
{ name: 'Hill Climb Racing', rating: 3.88 },
{ name: 'Angry Birds Space', rating: 3.88 },
{ name: 'Badland', rating: 4.33 }
];
// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));
Сортировка (более) сложных массивов объектов
Поскольку вы, вероятно, сталкиваетесь с более сложными структурами данных, такими как этот массив, я бы расширил решение.
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://stackru.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
Комбинируя динамическое решение Ege с идеей Vinay, вы получаете хорошее надежное решение:
Array.prototype.sortBy = function() {
function _sortByAttr(attr) {
var sortOrder = 1;
if (attr[0] == "-") {
sortOrder = -1;
attr = attr.substr(1);
}
return function(a, b) {
var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
return result * sortOrder;
}
}
function _getSortFunc() {
if (arguments.length == 0) {
throw "Zero length arguments not allowed for Array.sortBy()";
}
var args = arguments;
return function(a, b) {
for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
result = _sortByAttr(args[i])(a, b);
}
return result;
}
}
return this.sort(_getSortFunc.apply(null, arguments));
}
Использование:
// Utility for printing objects
Array.prototype.print = function(title) {
console.log("************************************************************************");
console.log("**** "+title);
console.log("************************************************************************");
for (var i = 0; i < this.length; i++) {
console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
}
}
// Setup sample data
var arrObj = [
{FirstName: "Zach", LastName: "Emergency", Age: 35},
{FirstName: "Nancy", LastName: "Nurse", Age: 27},
{FirstName: "Ethel", LastName: "Emergency", Age: 42},
{FirstName: "Nina", LastName: "Nurse", Age: 48},
{FirstName: "Anthony", LastName: "Emergency", Age: 44},
{FirstName: "Nina", LastName: "Nurse", Age: 32},
{FirstName: "Ed", LastName: "Emergency", Age: 28},
{FirstName: "Peter", LastName: "Physician", Age: 58},
{FirstName: "Al", LastName: "Emergency", Age: 51},
{FirstName: "Ruth", LastName: "Registration", Age: 62},
{FirstName: "Ed", LastName: "Emergency", Age: 38},
{FirstName: "Tammy", LastName: "Triage", Age: 29},
{FirstName: "Alan", LastName: "Emergency", Age: 60},
{FirstName: "Nina", LastName: "Nurse", Age: 54}
];
//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");
Еще один вариант:
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));
сортирует по возрастанию по умолчанию.
Вот мой взгляд на это:
В order
Параметр является необязательным и по умолчанию имеет значение "ASC" для возрастания.
function sortByProperty(array,property,order="ASC") {
return array.sort((a,b) => order === "ASC" ?
a[property] > b[property] ? 1 : a[property] < b[property] ? -1 : 0
: a[property] > b[property] ? -1 : a[property] < b[property] ? 1 : 0
);
}
СНИППЕТ
function sortByProperty(array,property,order="ASC") {
return array.sort((a,b) => order === "ASC" ?
a[property] > b[property] ? 1 : a[property] < b[property] ? -1 : 0
: a[property] > b[property] ? -1 : a[property] < b[property] ? 1 : 0
);
}
const rockStars = [
{ name: "Axl",
lastname: "Rose" },
{ name: "Elthon",
lastname: "John" },
{ name: "Paul",
lastname: "McCartney" },
{ name: "Lou",
lastname: "Reed" }
];
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));
Простая функция, которая сортирует массив объектов по свойству
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
Простой способ:
objs.sort(function(a,b) {
return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});
Видеть, что '.toLowerCase()'
необходимо предотвратить ошибки при сравнении строк.
Учитывая оригинальный пример:
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;
Дополнительные параметры desc для кода Ege Özcan
function dynamicSort(property, desc) {
if (desc) {
return function (a, b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
}
return function (a, b) {
return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
}
}