Search code examples
javascriptarrayssortinggroupinglodash

JavaScript array of objects sort by specific property and then group by custom priority values


I have array of objects and my requirement was to group users by status (online users should come first) while sort grouped users by name. I am able to achieve result but here I am using lodash concat function separately. Can anyone help to use it along with chain function?

Code:

  import _ from 'lodash';

  const { online = [], offline = [] } = _.chain(users)
    .sortBy([(e) => _.toLower(e.name)])
    .groupBy((e) => e.status)
    .value();
  const result = _.concat(online, offline);
  console.log('grouped users sorted by name => ', result);

Input:

let users = [
    {
        'name': 'C',
        'status': 'online'
    },
    {
        'name': 'd',
        'status': 'online'
    },
    {
        'name': 'a',
        'status': 'offline'
    },
    {
        'name': 'b',
        'status': 'online'
    },
    {
        'name': 'f',
        'status': 'offline'
    },
    {
        'name': 'e',
        'status': 'offline'
    }
];

Output:

[
    {
        'name': 'b',
        'status': 'online'
    },
    {
        'name': 'C',
        'status': 'online'
    },
    {
        'name': 'd',
        'status': 'online'
    },
    {
        'name': 'a',
        'status': 'offline'
    },
    {
        'name': 'e',
        'status': 'offline'
    },
    {
        'name': 'f',
        'status': 'offline'
    }
]

Thanks


Solution

  • You can do this easily without lodash too.

    You can use a customized sort function when calling the sort() function of an array. Create a sort string including a 0 for online users and a 1 for offline users followed by the name. Then use this sort string in the comparison.

    let users = [{
        'name': 'C',
        'status': 'online'
      },
      {
        'name': 'd',
        'status': 'online'
      },
      {
        'name': 'a',
        'status': 'offline'
      },
      {
        'name': 'b',
        'status': 'online'
      },
      {
        'name': 'f',
        'status': 'offline'
      },
      {
        'name': 'e',
        'status': 'offline'
      }
    ];
    
    users.sort((a, b) => {
      let sortStringA = (a.status.toUpperCase() == 'ONLINE' ? 0 : 1) + a.name.toUpperCase();
      let sortStringB = (b.status.toUpperCase() == 'ONLINE' ? 0 : 1) + b.name.toUpperCase();
      if (sortStringA < sortStringB) {
        return -1;
      }
      if (sortStringA > sortStringB) {
        return 1;
      }
      return 0;
    });
    
    console.log(users);