У меня есть массив объектов 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()
к моим объектам?
Написать собственную функцию сравнения достаточно просто:
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 );
Или inline (c/o Marco Demaio):
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) {
/* 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"));
На самом деле это уже отвечает на вопрос. Ниже часть написана, потому что многие люди связались со мной, жалуясь, что это не'т работать с несколькими параметрами]1.
Вы можете использовать функцию ниже, чтобы генерировать рода функций с множеством параметров сортировки.
function dynamicSortMultiple() {
/*
* save the arguments object as it will be overwritten
* note that arguments object is an array-like object
* consisting of the names of the properties to sort by
*/
var props = arguments;
return function (obj1, obj2) {
var i = 0, result = 0, numberOfProperties = props.length;
/* try getting a different result from 0 (equal)
* as long as we have extra properties to compare
*/
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(props[i])(obj1, obj2);
i++;
}
return result;
}
}
Что позволит вам сделать что-то вроде этого:
People.sort(dynamicSortMultiple("Name", "-Surname"));
Для счастливых среди нас, кто может использовать на ES6, который позволяет расширить собственные объекты:
class MyArray extends Array {
sortBy(...args) {
return this.sort(dynamicSortMultiple.apply(null, args));
}
}
Что бы включить эту:
MyArray.from(People).sortBy("Name", "-Surname");
[7]: https://github.com/zenparsing/es-function-bind на "предложение оператора привязать"и
В на 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)
});
используйте подчеркивания, небольшие и удивительные...
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' );
Дон'т понимаю, почему люди все усложняют:
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;
});
Поменять оператора, чтобы он отсортированный по обратном алфавитном порядке.
Если у вас есть дублирующиеся фамилии, вы можете отсортировать их по имени.
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;
});
Простое и быстрое решение этой проблемы, используя прототип наследования:
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"}]
Обновление: больше не изменяет исходный массив.
В 2018 году есть гораздо более короткий и элегантное решение. Просто использовать. Массив.прототип.сортировать().
Пример:
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;
});
Вместо использования пользовательской функции сравнения можно также создать тип объекта с пользовательским методом 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();
(https://lodash.com/docs/4.17.10#orderBy)
Этот метод, как _.sortBy за исключением того, что он позволяет определить порядок сортировки для iteratees для сортировки. Если заказов не определено, все значения сортируются в порядке возрастания. В противном случае, уточнить порядок "по убыванию" и для спуска или "АСК" и в порядке возрастания соответствующих значений.
Доводы
коллекция (массив|объект): коллекция для перебора. [iteratees=[_.идентичности]] (массив[]|работа[]|объекта[]|String []) и: в iteratees для сортировки. [заказы] (строка[]): сортировка заказов iteratees.
Возвращает
(Массив): возвращает новый отсортированный массив.
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']);
Lodash.js (Расширенная версия Underscore.js)
Это's хорошо, чтобы не добавить рамки для любого простого куска логики, но и опираясь на хорошо проверенные коммунальных структур, ускорить разработку и сократить количество письменных ошибок, не стыдно.
Лодашь производит очень чистый код и способствует более функциональное программирование стиль, что приводит к меньшим количеством ошибок. В одного мимолетного взгляда становится ясно, что намерение, если код.
ОП'ы вопрос может просто быть решена как:
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}}
];
Теперь мы можем использовать _.недвижимость пользователей стенография.возраст
, чтобы указать путь к свойству, которое должно соответствовать. Мы будем сортировать объекты пользователя, вложенной лет собственность. Да, это позволяет использовать вложенные соответствия собственность!
const sortedObjs = _.sortBy(users, ['user.age']);
Хочу его вспять? Нет проблем. Использования _.обратный.
const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));
Хотите совместить, используя сцепление вместо этого?
const sortedObjs = _.chain(users).sortBy('user.age').reverse().value();
Есть много хороших ответов здесь, но я хотел бы отметить, что их можно удлинить очень просто добиться много более сложную сортировку. Единственное, что вам нужно сделать, это использовать или оператора к функции сравнения цепь следующим образом:
objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )
Где фн1,
фн2`, ... это такие функции, которые возвращают [-1,0,1]. Это выливается в "сортировка по фн1-то", то "сортировка по фн2-то", который практически равен порядка в 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])
Эта функция может быть расширена для поддержки числовые поля, корпус sensitity, произвольные типы данных и т. д.
Вы можете использовать его с цепочки их приоритет сортировки:
// 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 с функциональным подходом может принять вас долгий путь без внешних библиотек или сложного кода. Она также очень эффективна, так как нет разбора строк должно быть сделано
Пример Использования:
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;
};
};
У меня есть кусок кода, который работает для меня:
arr.sort((a, b) => a.name > b.name)
Обновление: не работает всегда, так что это не правильно :(
Я не'т видел именно такой подход предлагал, так вот'ы лаконичный способ сравнения я использую, что работает для String
и количество
:
в
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) => {
const fa = fn(a)
const fb = fn(b)
return -(fa < fb) || +(fa > fb)
}
const getLastName = o => o.last_nom
const sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
в
Здесь'ы объяснение sortBy()
:
sortBy()
принимает ФН
, который выбирает значение из объекта для использования в качестве сравнения, и возвращает функцию, которая может быть передана непосредственно в массив.прототип.сортировать(). В этом примере, мы're, используя
о'.last_nomв качестве значения для сравнения, поэтому, когда мы получаем два объекта через массив.прототип.сортировать()
таких как
{ first_nom: 'Lazslo', last_nom: 'Jamf' }
и
{ first_nom: 'Pig', last_nom: 'Bodine' }
мы используем
(a, b) => {
const fa = fn(a)
const fb = fn(b)
return -(fa < fb) || +(fa > fb)
}
чтобы сравнить их.
Вспомнив, что ФН = о => о'.last_nom`, мы можем расширить функции сравнения в эквиваленте
(a, b) => {
const fa = a.last_nom
const fb = b.last_nom
return -(fa < fb) || +(fa > fb)
}
Оператор логическое или ||
имеет короткое замыкание функциональность, что'ы очень полезно здесь. Потому что, как он работает, тело функции выше означает
if (fa < fb) return -1
return +(fa > fb)
Так что если ФА < ФБмы вернемся
-1, если
Альфа > ФБ-тогда мы вернемся +1
, а если ФА == ФБ", затем "Альфа < ФБ" и " ФА > ФБ
имеют значение false
, поэтому он возвращает +0
.
В качестве дополнительного бонуса, здесь's в эквивалент в ECMAScript 5 без функции стрелка, который, к сожалению, более подробный:
в
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) {
var fa = fn(a)
var fb = fn(b)
return -(fa < fb) || +(fa > fb)
}
}
var getLastName = function (o) { return o.last_nom }
var sortByLastName = sortBy(getLastName)
objs.sort(sortByLastName)
console.log(objs.map(getLastName))
в
Я знаю, что этот вопрос является слишком стар, но я не'т вижу никакой реализации похож на мой. Эта версия основана на преобразование Шварца идиома.
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'));
Поскольку вы, вероятно, столкнетесь с более сложными структурами данных, как массив, я хотел расширить решение.
больше разъемный версия на основе @ЕГЭ-Özcan's очень прекрасный ответить.
Проблема ## Я столкнулся ниже и не мог't изменить его. Я также не хочу, чтобы сгладить временного объекта. Я не хочу использовать подчеркивания / лодашь, главным образом, из соображений производительности и веселья, чтобы реализовать это сам.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
Цель ###
Цель состоит в том, чтобы разобраться с ним в первую очередь люди.Имя.имяи затем
людей.Имя.фамилия`
Препятствия ###
Итак, в основе решения используется скобочная нотация для вычисления свойств для сортировки динамически. Здесь, однако, мы должны были бы динамически построить скобочная нотация кроме того, поскольку вы ожидали бы некоторые, как люди['название.имя']
будет работать - что не'т.
Просто делаешь люди['название']['имя']
, с другой стороны, статичен и только позволяет спуститься в Н-го уровня.
Решение ## Главным здесь будет идти вниз по дереву объектов и определить значение последнего листа, вы должны указать, а также любой промежуточный лист.
var People = [
{Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
{Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
{Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];
People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
// { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
// { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]
// same logic as above, but strong deviation for dynamic properties
function dynamicSort(properties) {
var sortOrder = 1;
// determine sort order by checking sign of last element of array
if(properties[properties.length - 1][0] === "-") {
sortOrder = -1;
// Chop off sign
properties[properties.length - 1] = properties[properties.length - 1].substr(1);
}
return function (a,b) {
propertyOfA = recurseObjProp(a, properties)
propertyOfB = recurseObjProp(b, properties)
var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
return result * sortOrder;
};
}
/**
* Takes an object and recurses down the tree to a target leaf and returns it value
* @param {Object} root - Object to be traversed.
* @param {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
* @param {Number} index - Must not be set, since it is implicit.
* @return {String|Number} The property, which is to be compared by sort.
*/
function recurseObjProp(root, leafs, index) {
index ? index : index = 0
var upper = root
// walk down one level
lower = upper[leafs[index]]
// Check if last leaf has been hit by having gone one step too far.
// If so, return result from last step.
if (!lower) {
return upper
}
// Else: recurse!
index++
// HINT: Bug was here, for not explicitly returning function
// https://stackoverflow.com/a/17528613/3580261
return recurseObjProp(lower, leafs, index)
}
/**
* Multi-sort your array by a set of properties
* @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
* @return {Number} Number - number for sort algorithm
*/
function dynamicMultiSort() {
var args = Array.prototype.slice.call(arguments); // slight deviation to base
return function (a, b) {
var i = 0, result = 0, numberOfProperties = args.length;
// REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
// Consider: `.forEach()`
while(result === 0 && i < numberOfProperties) {
result = dynamicSort(args[i])(a, b);
i++;
}
return result;
}
}
Рабочий пример [на JSBin](http://jsbin.com/lotifa/2/edit?js консоль)
Еще один вариант:
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));
сортирует по возрастанию по умолчанию.
Простой способ:
objs.sort(function(a,b) {
return b.last_nom.toLowerCase() < a.last_nom.toLowerCase();
});
Увидим, что'.столоверчением()' - это необходимо для предотвращения Омеги в сравнении строк.
Простую функцию, которая сортирует массив объектов по свойству
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