Как отсортировать массив объектов JavaScript по вложенным свойствам объекта? - PullRequest
27 голосов
/ 22 февраля 2011

У меня есть эта функция для сортировки массива объектов 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'].

Знаете ли вы, как я могу решить эту проблему и заставить мою функцию работать со свойствами вложенных объектов?

Заранее спасибо

Ответы [ 8 ]

23 голосов
/ 22 февраля 2011

Вы можете разделить 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;
};
7 голосов
/ 22 февраля 2011

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

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, { .. });
4 голосов
/ 04 января 2016

Используйте Array.prototype.sort() с пользовательской функцией сравнения, чтобы сначала выполнить сортировку по убыванию:

champions.sort(function(a, b) { return b.level - a.level }).slice(...

Еще лучше с ES6:

champions.sort((a, b) => b.level - a.level).slice(...
3 голосов
/ 15 ноября 2014

Вы можете использовать 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]]
0 голосов
/ 16 марта 2019

если у вас есть массив объектов типа

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"));
0 голосов
/ 22 февраля 2011

Это мой модифицированный код.

// 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;
        }
    });
};
0 голосов
/ 22 февраля 2011

Попробуйте это (с помощью рекурсивной функции получить вложенное значение, вы можете передать вложенное свойство как 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;
        }
    });
};
0 голосов
/ 22 февраля 2011

Будет ли это соответствовать вашим потребностям?

// 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;
        }
    });
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...