How can I use lodash/underscore to sort by multiple nested fields?

安稳与你 提交于 2019-12-03 14:38:18

问题


I want to do something like this:

var data = [
    {
        sortData: {a: 'a', b: 2}
    },
    {
        sortData: {a: 'a', b: 1}
    },
    {
        sortData: {a: 'b', b: 5}
    },
    {
        sortData: {a: 'a', b: 3}
    }
];

data = _.sortBy(data, ["sortData.a", "sortData.b"]);

_.map(data, function(element) {console.log(element.sortData.a + " " + element.sortData.b);});

And have it output this:

"a 1"
"a 2"
"a 3"
"b 5"

Unfortunately, this doesn't work and the array remains sorted in its original form. This would work if the fields weren't nested inside the sortData. How can I use lodash/underscore to sort an array of objects by more than one nested field?

I've turned this into a lodash feature request: https://github.com/lodash/lodash/issues/581


回答1:


There is a _.sortByAll method in lodash version 3:

https://github.com/lodash/lodash/blob/3.10.1/doc/README.md#_sortbyallcollection-iteratees

Lodash version 4, it has been unified:

https://lodash.com/docs#sortBy

Other option would be to sort values yourself:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

function compareValues(v1, v2) {
    return (v1 > v2) 
        ? 1 
        : (v1 < v2 ? -1 : 0);
};


var data = [
    { a: 2, b: 1 },
    { a: 2, b: 2 },
    { a: 1, b: 3 }
];

data.sort(function (x, y) {
    var result = compareValues(x.a, y.a);

    return result === 0 
        ? compareValues(x.b, y.b) 
        : result;
});

// data after sort:
// [
//     { a: 1, b: 3 },
//     { a: 2, b: 1 },
//     { a: 2, b: 2 }
// ];



回答2:


Update: See the comments below, this is not a good solution in most cases.


Someone kindly answered in the issue I created. Here's his answer, inlined:

_.sortBy(data, function(item) {
   return [item.sortData.a, item.sortData.b];
});

I didn't realize that you're allowed to return an array from that function. The documentation doesn't mention that.




回答3:


If you need to specify the sort direction, you can use _.orderBy with the array of functions syntax from Lodash 4.x:

_.orderBy(data, [
  function (item) { return item.sortData.a; },
  function (item) { return item.sortData.b; }
], ["asc", "desc"]);

This will sort first ascending by property a, and for objects that have the same value for property a, will sort them descending by property b.

It works as expected when the a and b properties have different types.

Here is a jsbin example using this syntax.




回答4:


The awesome, simple way is:

_.sortBy(data, [function(item) {
    return item.sortData.a;
}, function(item) {
    return item.sortData.b;
}]);

I found it from check the source code of lodash, it always check the function one by one.

Hope that help.




回答5:


With ES6 easy syntax and lodash

sortBy(item.sortData, (item) => (-item.a), (item) => (-item.b))



回答6:


I think this could work in most cases with underscore:

var properties = ["sortData.a", "sortData.b"];
data = _.sortBy(data, function (d) {
    var predicate = '';
    for (var i = 0; i < properties.length; i++)
    {
        predicate += (i == properties.length - 1 
                           ? 'd.' + properties[i]
                           : 'd.' + properties[i] + ' + ')
    }
    return eval(predicate)
});

It works and you can see it in Plunker




回答7:


If the problem is an integer is converted to a string, add zeroes before the integer to make it have the same length as the longest in the collection:

var maxLength = _.reduce(data, function(result, item) {
    var bString = _.toString(item.sortData.b);
    return result > bString.length ? result : bString.length;            
}, 0);

_.sortBy(data, function(item) {
    var bString = _.toString(item.sortData.b);
    if(maxLength > bString.length) {
        bString = [new Array(maxLength - bString.length + 1).join('0'), bString].join('');
    }

    return [item.sortData.a, bString];
});


来源:https://stackoverflow.com/questions/24111535/how-can-i-use-lodash-underscore-to-sort-by-multiple-nested-fields

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!