Как отсортировать массив объектов JavaScript с помощью свойства вложенного объекта?
У меня есть эта функция для сортировки массива JavaScript на основе свойства:
// arr is the array of objects, prop is the property to sort by
var sort = function (prop, arr) {
arr.sort(function (a, b) {
if (a[prop] < b[prop]) {
return -1;
} else if (a[prop] > b[prop]) {
return 1;
} else {
return 0;
}
});
};
Он работает с массивами следующим образом:
sort('property', [
{property:'1'},
{property:'3'},
{property:'2'},
{property:'4'},
]);
Но я хочу иметь возможность сортировать также по вложенным свойствам, например, что-то вроде:
sort('nestedobj.property', [
{nestedobj:{property:'1'}},
{nestedobj:{property:'3'}},
{nestedobj:{property:'2'}},
{nestedobj:{property:'4'}}
]);
Однако это не работает, потому что невозможно сделать что-то вроде object['nestedobj.property']
, оно должно быть object['nestedobj']['property']
.
Вы знаете, как я могу решить эту проблему и заставить мою функцию работать со свойствами вложенных объектов?
Заранее спасибо
Ответы
Ответ 1
Вы можете разделить prop
на .
и перебрать массив, обновляя a
и b
со следующим вложенным свойством во время каждой итерации.
Пример: http://jsfiddle.net/x8KD6/1/
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) { a = a[prop[i]]; b = b[prop[i]]; i++; }
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
Ответ 2
Вместо передачи свойства в виде строки передайте функцию, которая может извлечь свойство из объекта верхнего уровня.
var sort = function (propertyRetriever, arr) {
arr.sort(function (a, b) {
var valueA = propertyRetriever(a);
var valueB = propertyRetriever(b);
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
});
};
Вызывать как,
var simplePropertyRetriever = function(obj) {
return obj.property;
};
sort(simplePropertyRetriever, { .. });
Или используя вложенный объект,
var nestedPropertyRetriever = function(obj) {
return obj.nestedObj.property;
};
sort(nestedPropertyRetriever, { .. });
Ответ 3
Вы можете использовать Agile.js для такого рода вещей.
Фактически вы передаете выражение вместо обратного вызова, оно обрабатывает вложенные свойства и выражение javascript очень хорошо.
Использование: _.orderBy(array, expression/callback, reverse[optional])
Пример:
var orders = [
{ product: { price: 91.12, id: 1 }, date: new Date('01/01/2014') },
{ product: { price: 79.21, id: 2 }, date: new Date('01/01/2014') },
{ product: { price: 99.90, id: 3 }, date: new Date('01/01/2013') },
{ product: { price: 19.99, id: 4 }, date: new Date('01/01/1970') }
];
_.orderBy(orders, 'product.price');
// → [orders[3], orders[1], orders[0], orders[2]]
_.orderBy(orders, '-product.price');
// → [orders[2], orders[0], orders[1], orders[3]]
Ответ 4
Будет ли это соответствовать вашим потребностям?
// arr is the array of objects, prop is the property to sort by
var sort = function (nestedObj, prop, arr) {
arr.sort(function (a, b) {
if (a[nestedObj][prop] < b[nestedObj][prop]) {
return -1;
} else if (a[nestedObj][prop] > b[nestedObj][prop]) {
return 1;
} else {
return 0;
}
});
};
Ответ 5
Попробуйте (используя рекурсивную функцию для получения вложенного значения, вы можете передать вложенное свойство как nestedobj.property):
Вы можете использовать это для любого уровня иерархии
// arr is the array of objects, prop is the property to sort by
var getProperty = function(obj, propNested){
if(!obj || !propNested){
return null;
}
else if(propNested.length == 1) {
var key = propNested[0];
return obj[key];
}
else {
var newObj = propNested.shift();
return getProperty(obj[newObj], propNested);
}
};
var sort = function (prop, arr) {
arr.sort(function (a, b) {
var aProp = getProperty(a, prop.split("."));
var bProp = getProperty(a, prop.split("."));
if (aProp < bProp) {
return -1;
} else if (aProp > bProp) {
return 1;
} else {
return 0;
}
});
};
Ответ 6
Это мой код модификации.
// arr is the array of objects, prop is the property to sort by
var s = function (prop, arr) {
// add sub function for get value from obj (1/2)
var _getVal = function(o, key){
var v = o;
var k = key.split(".");
for(var i in k){
v = v[k[i]];
}
return v;
}
return arr.sort(function (a, b) {
// get value from obj a, b before sort (2/2)
var aVal = _getVal(a, prop);
var bVal = _getVal(b, prop);
if (aVal < bVal) {
return -1;
} else if (aVal > bVal) {
return 1;
} else {
return 0;
}
});
};
Ответ 7
Используйте Array.prototype.sort()
с пользовательской функцией сравнения, чтобы сначала выполнить сортировку по убыванию:
champions.sort(function(a, b) { return b.level - a.level }).slice(...
Еще лучше с ES6:
champions.sort((a, b) => b.level - a.level).slice(...