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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5073799/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:31:57  来源:igfitidea点击:

How to sort a JavaScript array of objects by nested object property?

javascriptarrayssorting

提问by VerizonW

I have this function to sort a JavaScript array of objects based on a property:

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

It works with arrays like this:

它适用于这样的数组:

sort('property', [
    {property:'1'},
    {property:'3'},
    {property:'2'},
    {property:'4'},
]);

But I want to be able to sort also by nested properties, for example something like:

但我也希望能够按嵌套属性进行排序,例如:

sort('nestedobj.property', [
    {nestedobj:{property:'1'}},
    {nestedobj:{property:'3'}},
    {nestedobj:{property:'2'}},
    {nestedobj:{property:'4'}}
]);

However this doesn't work because it is not possible to do something like object['nestedobj.property'], it should be object['nestedobj']['property'].

但是这不起作用,因为不可能做类似的事情object['nestedobj.property'],它应该是object['nestedobj']['property']

Do you know how could I solve this problem and make my function work with properties of nested objects?

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

Thanks in advance

提前致谢

采纳答案by user113716

You can split the propon ., and iterate over the Array updating the aand bwith the next nested property during each iteration.

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

Example:http://jsfiddle.net/x8KD6/1/

示例: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;
};

回答by Anurag

Instead of passing the property as a string, pass a function that can retrieve the property from the top level object.

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

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

Invoke as,

调用为,

var simplePropertyRetriever = function(obj) {
    return obj.property;
};

sort(simplePropertyRetriever, { .. });

Or using a nested object,

或者使用嵌套对象,

var nestedPropertyRetriever = function(obj) {
    return obj.nestedObj.property;
};

sort(nestedPropertyRetriever, { .. });

回答by rat

Use Array.prototype.sort()with a custom compare function to do the descending sort first:

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

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

Even nicer with ES6:

使用 ES6 更好:

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

回答by a8m

You can use Agile.jsfor this kind of things.
Actually you pass an expression instead of callback, it's handle nested properties and javascript expression in a very nice-ish way.

您可以将Agile.js用于此类事情。
实际上,您传递的是表达式而不是回调,它以一种非常漂亮的方式处理嵌套属性和 javascript 表达式。

Usage:_.orderBy(array, expression/callback, reverse[optional])

用法:_.orderBy(array, expression/callback, reverse[optional])

Example:

例子:

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]]

回答by Mas

if you have array of objects like

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

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
        }
    }];

you can use simply

你可以简单地使用

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;
    }

and call it

并称之为

for direct objects

对于直接对象

objs.sort(nestedSort("last_nom"));
objs.sort(nestedSort("last_nom", null, "desc"));

for nested objects

对于嵌套对象

objs.sort(nestedSort("moreDetails", "age"));
objs.sort(nestedSort("moreDetails", "age", "desc"));

回答by Chandu

Try this (used a recursive function to get nested value, you can pass the nested property as nestedobj.property): You can use this for any level of hierarchy

试试这个(使用递归函数来获取嵌套值,您可以将嵌套属性作为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;
        }
    });
};

回答by diewland

This is my modify code.

这是我的修改代码。

// 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;
        }
    });
};

回答by jessegavin

Would this meet your needs?

这会满足您的需求吗?

// 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;
        }
    });
};