ES6 groupBy, partition, sort list of objects

Viewed 587

I am trying to figure out an elegant way in ES6 to sort an array of objects based on specified values. Here's the scenario:

const list = [
{
"name": "john",
"lastName": "smith"
}, {
"name": "tony",
"lastName": "smith"
}, {
"name": "tony",
"lastName": "grey"
}, {
"name": "mary",
"lastName": "smith"
}, {
"name": "john",
"lastName": "x"
}, {
"name": "tom",
"lastName": "y"
}
, {
"name": "mary",
"lastName": "x"
}
]

let orderList = [{"name":["john","mary"]}, {"lastName":["x"]}];

So, basically sort the result by the names(John, Mary) and then sort that result by lastName(x), but the name sorting still takes precedence. The result should look like this:

[
  {
   "name": "john",
   "lastName": "x"
  }, {
   "name": "john",
   "lastName": "smith"
  }, {
    "name": "mary",
   "lastName": "x"
  }, {
   "name": "mary",
   "lastName": "smith"
  }, {
   "name": "tony",
   "lastName": "smith"
   }, {
    "name": "tony",
    "lastName": "grey"
   }, {
    "name": "tom",
    "lastName": "y"
   }
 ]

I have already tried doing something with group by, but it's a manual process for each name and last name.

_.groupBy(list , {"name": "john"});

I also tried experimenting with array reduce, but can't seem to find a good dynamic solution.

const sortArr = ['john', 'mary'];
const sortedList= list.reduce((result, element) => {
   let index = sortArr.findIndex(x => x === element.name);
   result[index !== -1
      ? index
      : result.length - 1].push(element); 
     return result;
       },[  [], [], [] ]);

Any help is appreciated. Thanks

1 Answers

You could use Array#sort and take an iterative approach for sorting first by name and then by lastName.

This proposal works with a check if a property is in an array and sorts these value to top by taking the delta of the indices. This is repeated until the delta is not zero or the array of order has ended.

For getting the delta, an Array#indexOf search is made and if -1, the value for not found item, is replaced with Infinity, because this item has to be sorted to the end of the array. The items with a found index are sorted according to the index.

For a bit faster sorting, objects with a single key/value pair are converted to an array with key and value.

var list = [{ name: "john", lastName: "smith" }, { name: "tony", lastName: "smith" }, { name: "tony", lastName: "grey" }, { name: "mary", lastName: "smith" }, { name: "john", lastName: "x" }, { name: "tom", lastName: "y" }, { name: "mary", lastName: "x" }],
    orderList = [{ name: ["john", "mary"] }, { lastName: ["x"] }],
    order = orderList.map(o => (k => [k, o[k]])(Object.keys(o)[0]));

list.sort((a, b) => {
    var d;
    order.some(([k, v]) =>
        d = (v.indexOf(a[k]) + 1 || Infinity) - (v.indexOf(b[k]) + 1 || Infinity)
    );
    return d;
});

console.log(list);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related