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

Posted

技术标签:

【中文标题】如何通过嵌套对象属性对 JavaScript 对象数组进行排序?【英文标题】:How to sort a JavaScript array of objects by nested object property? 【发布时间】:2022-01-18 13:13:17 【问题描述】:

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

这能满足您的需求吗?

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

【讨论】:

【参考方案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】:

您可以在. 上拆分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) 这似乎不适用于不同长度的属性值。例如。 nestedobj:property:'g', nestedobj:property:'F', nestedobj:property:'abcd', nestedobj:property:'abba'【参考方案4】:

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

【讨论】:

【参考方案5】:

这是我的修改代码。

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

【讨论】:

【参考方案6】:

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

【讨论】:

【参考方案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(...

【讨论】:

【参考方案8】:

如果你有类似的对象数组

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

【讨论】:

【参考方案9】:

var objectsArr = [
  nestedobj:property:'1',
  nestedobj:property:'3',
  nestedobj:property:'2',
  nestedobj:property:'4'
];

function getFromPath(obj, path) 
  let r = obj;
  path.forEach(key =>  r = r[key])
  return r


function sortObjectsArr(objectsArray, ...path) 
  objectsArray.sort((a, b) => getFromPath(a, path) - getFromPath(b, path))


sortObjectsArr(objectsArr, 'nestedobj', 'property');

console.log(objectsArr);

不幸的是,我没有找到任何好的方法来使用参数来访问嵌套对象的属性。 想提一下,如果键在传递的对象中可用,可以进行一些检查,但这取决于谁以及如何实现。

【讨论】:

以上是关于如何通过嵌套对象属性对 JavaScript 对象数组进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何过滤 JavaScript 中的嵌套对象属性?

如何使用javascript在嵌套对象数组中按属性分配值

javascript 通过嵌套键对对象数组进行排序

如何在javascript中对嵌套的对象数组进行排序?

如何根据 Aurelia/Typescript 中的嵌套属性对对象数组进行排序

按嵌套属性对对象的对象进行排序