Shoaib Chikate
Shoaib Chikate

Reputation: 8975

How to sort on multiple columns using JavaScript sort?

I have following array that needs to be sorted with respect to search text 'John'.

  {id: 1, firstName: 'User', lastName: 'John', nickName: 'Smith'},
  {id: 2, firstName: 'Test', lastName: 'John', nickName: 'Andrew'},
  {id: 3, firstName: 'Test', lastName: 'Zch', nickName: 'John'},
  {id: 4, firstName: 'Test', lastName: 'Mason', nickName: 'John'},
  {id: 5, firstName: 'John', lastName: 'Doe'},


];

Expected Output:

Array should be first sorted with nickName (with search text) then lastName(with search text). If nickName is not present then it should sorted with respect to firstName(with search text) with ASC sorting order. Note: It should consider search text word as 'John'

This sort resembles like Search with Sort in your mobile's contact app

[
  // sort with nickName as higher relevance considering search text as John
  {id: 4, firstName: 'Test', lastName: 'Mason', nickName: 'John'},
  {id: 3, firstName: 'Test', lastName: 'Zch', nickName: 'John'},
  // sort with lastName considering search text
  {id: 2, firstName: 'Test', lastName: 'John', nickName: 'Andrew'},
  {id: 1, firstName: 'User', lastName: 'John', nickName: 'Smith'},
  // sort  with firstName as nickName is null
  {id: 5, firstName: 'John', lastName: 'Doe'},



];

I tried localeMethod

function sortByLocale(user1, user2) {
   var sortByNickName = user1.nickName.toLowerCase().localeCompare(user2.nickName.toLowerCase());
   var sortByLastName = user1.lastName.toLowerCase().localeCompare(user2.lastName.toLowerCase());

   return sortByNickName || sortByLastName;
}

But the result is not considering search text while sorting. One approach, I can see is creating three different arrays and sort them and combined those sorted array Any helps would be appreciated.

Edit: Not considering the non-matched object with search text value

Upvotes: 1

Views: 410

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386680

You could take two iterations for the wanted order

  1. one for the wanted string
  2. for the order of the rest

var data = [{ id: 1, firstName: 'User', lastName: 'John', nickName: 'Smith' },
  { id: 2, firstName: 'Test', lastName: 'John', nickName: 'Andrew' },
  { id: 3, firstName: 'Test', lastName: 'Zch', nickName: 'John' },
  { id: 4, firstName: 'Test', lastName: 'Mason', nickName: 'John' },
  { id: 5, firstName: 'John', lastName: 'Doe' }
],
    search = 'john',
    check = (s => (o, k) => (o[k] || '').toLowerCase() === search)(search),
    keys = ['nickName', 'lastName', 'firstName'];

data.sort((a, b) => {
    const
        fns = [
            k => d = check(b, k) - check(a, k),
            k => d = (a[k] || '').localeCompare(b[k] || '')
        ];
    let d = 0;
    fns.some(fn => keys.some(fn));
    return d;
});

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

Upvotes: 1

Dmitry Reutov
Dmitry Reutov

Reputation: 3032

Just add first search by name

function checkSearch (value)  {
   return (value.nickName === 'John') * -3 ||
      (value.lastName === 'John') * -2 ||
      (value.firstName === 'John') * -1 ||
      0
}

function sortByLocale(user1, user2) {
   var sortBySearch = checkSearch(user1) - checkSearch(user2)

   var sortByNickName = (user1.nickName || '').toLowerCase().localeCompare((user2.nickName || '').toLowerCase());
   var sortByLastName = user1.lastName.toLowerCase().localeCompare(user2.lastName.toLowerCase());

   return sortBySearch || sortByNickName || sortByLastName;
}

Upvotes: 1

Related Questions