如何按嵌套对象属性对 JavaScript 对象数组进行排序?

IT技术 javascript arrays sorting
2021-03-04 06:51:10

我有这个函数可以根据属性对 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']

你知道我如何解决这个问题并使我的函数与嵌套对象的属性一起工作吗?

提前致谢

6个回答

您可以分割prop.遍历数组更新,并ab每个迭代过程中的下一个嵌套属性。

示例: 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;
};
@VerizonW:很高兴它奏效了。是的,我喜欢尽可能避免函数调用。使事情变得活泼。:o)
2021-04-17 06:51:10
这似乎不适用于不同长度的属性值。例如 {nestedobj:{property:'g'}}, {nestedobj:{property:'F'}}, {nestedobj:{property:'abcd'}}, {nestedobj:{property:'abba'}}
2021-04-24 06:51:10
感谢这有效并且比建议的其他选项更快。
2021-05-11 06:51:10

不是将属性作为字符串传递,而是传递一个可以从顶级对象中检索属性的函数。

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, { .. });

使用Array.prototype.sort()自定义比较函数首先进行降序排序:

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

使用 ES6 更好:

champions.sort((a, b) => b.level - a.level).slice(...

您可以将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]]

如果你有像这样的对象数组

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