Underscore: sortBy() based on multiple attributes

2019-01-06 08:43发布

I am trying to sort an array with objects based on multiple attributes. I.e if the first attribute is the same between two objects a second attribute should be used to comapare the two objects. For example, consider the following array:

var patients = [
             [{name: 'John', roomNumber: 1, bedNumber: 1}],
             [{name: 'Lisa', roomNumber: 1, bedNumber: 2}],
             [{name: 'Chris', roomNumber: 2, bedNumber: 1}],
             [{name: 'Omar', roomNumber: 3, bedNumber: 1}]
               ];

Sorting these by the roomNumber attribute i would use the following code:

var sortedArray = _.sortBy(patients, function(patient) {
    return patient[0].roomNumber;
});

This works fine, but how do i proceed so that 'John' and 'Lisa' will be sorted properly?

10条回答
疯言疯语
2楼-- · 2019-01-06 09:24

I think you'd better use _.orderBy instead of sortBy:

_.orderBy(patients, ['name', 'roomNumber'], ['asc', 'desc'])
查看更多
We Are One
3楼-- · 2019-01-06 09:26

Simple Example from http://janetriley.net/2014/12/sort-on-multiple-keys-with-underscores-sortby.html (courtesy of @MikeDevenney)

Code

var FullySortedArray = _.sortBy(( _.sortBy(array, 'second')), 'first');

With Your Data

var FullySortedArray = _.sortBy(( _.sortBy(patients, 'roomNumber')), 'name');
查看更多
地球回转人心会变
4楼-- · 2019-01-06 09:29

sortBy says that it is a stable sort algorithm so you should be able to sort by your second property first, then sort again by your first property, like this:

var sortedArray = _(patients).chain().sortBy(function(patient) {
    return patient[0].name;
}).sortBy(function(patient) {
    return patient[0].roomNumber;
}).value();

When the second sortBy finds that John and Lisa have the same room number it will keep them in the order it found them, which the first sortBy set to "Lisa, John".

查看更多
欢心
5楼-- · 2019-01-06 09:33

Just return an array of properties you want to sort with:

ES6 Syntax

var sortedArray = _.sortBy(patients, patient => [patient[0].name, patient[1].roomNumber])

ES5 Syntax

var sortedArray = _.sortBy(patients, function(patient) { 
    return [patient[0].name, patient[1].roomNumber]
})

This does not have any side effects of converting a number to a string.

查看更多
劫难
6楼-- · 2019-01-06 09:35

Perhaps underscore.js or just Javascript engines are different now than when these answers were written, but I was able to solve this by just returning an array of the sort keys.

var input = [];

for (var i = 0; i < 20; ++i) {
  input.push({
    a: Math.round(100 * Math.random()),
    b: Math.round(3 * Math.random())
  })
}

var output = _.sortBy(input, function(o) {
  return [o.b, o.a];
});

// output is now sorted by b ascending, a ascending

In action, please see this fiddle: https://jsfiddle.net/mikeular/xenu3u91/

查看更多
劳资没心,怎么记你
7楼-- · 2019-01-06 09:36

I know I'm late to the party, but I wanted to add this for those in need of a clean-er and quick-er solution that those already suggested. You can chain sortBy calls in order of least important property to most important property. In the code below I create a new array of patients sorted by Name within RoomNumber from the original array called patients.

var sortedPatients = _.chain(patients)
  .sortBy('Name')
  .sortBy('RoomNumber')
  .value();
查看更多
登录 后发表回答