Amelia W
Amelia W

Reputation: 101

Sort an array of objects with 6 conditions

I am super stuck with sorting my array of objects.

const users = useMemo(() => [userDetails, ...otherParticipants]
        .sort((a, b) => b.isTyping - a.isTyping)
        .sort((a, b) => b.liveDetails.status - a.liveDetails.status)
        .sort((a, b) => b.hasRaisedHand - a.hasRaisedHand)
        .sort((a, b) => b.isOnline - a.isOnline)     
, [userDetails, otherParticipants])

I tried chaining sorts and it worked a bit. Then I tried conditional, but nothing seemed to work with all that I needed to sort. I would really appreciate some guidance. Sorry for the long post...

[
        {
        
           isOnline: true,
           hasRaisedHand: false,
           isTyping: false,
           liveDetails: {
              status: 'pending',
              camera: false,
              mic: false,
           },
        },
          {
        
           isOnline: true,
           hasRaisedHand: false,
           isTyping: false,
           liveDetails: {
              status: 'active',
              camera: false,
              mic: false,
           },
        },
    {
        
           isOnline: false,
           hasRaisedHand: false,
           isTyping: false,
           liveDetails: {
              status: 'disabled',
              camera: false,
              mic: false,
           },
        },
    {
        
           isOnline: true,
           hasRaisedHand: false,
           isTyping: true,
           liveDetails: {
              status: 'disabled',
              camera: false,
              mic: false,
           },
        },

    {
        
           isOnline: true,
           hasRaisedHand: true,
           isTyping: false,
           liveDetails: {
              status: 'disabled',
              camera: false,
              mic: false,
           },
        },
]

This is the order I need the objects sorted into:

isTyping: true
status: 'active'
status: 'pending'
hasRaisedHand: true
isOnline: true
isOnline: false

example: an object that has the key isTyping: true should be in front of the object that has a status: 'pending'.

example 2: if an object has status: 'pending' but also has isTyping: true, it should be in the front of the array.

this is the order the objects need to sort into, but I cant seem to get it to work at all.

This would be the order I need:

    [
                
                  
            
            {
                
                   isOnline: true,
                   hasRaisedHand: false,
                   **isTyping: true,**
                   liveDetails: {
                      status: 'disabled',
                      camera: false,
                      mic: false,
                   },
                },
    {
                
                   isOnline: true,
                   hasRaisedHand: false,
                   isTyping: false,
                   liveDetails: {
                      **status: 'active',**
                      camera: false,
                      mic: false,
                   },
                },
    {
                
                   isOnline: true,
                   hasRaisedHand: false,
                   isTyping: false,
                   liveDetails: {
                      **status: 'pending',**
                      camera: false,
                      mic: false,
                   },
                },
        
            {
                
                   isOnline: true,
                   **hasRaisedHand: true**,
                   isTyping: false,
                   liveDetails: {
                      status: 'disabled',
                      camera: false,
                      mic: false,
                   },
                },
{
                
                   **isOnline: true,**
                   hasRaisedHand: false,
                   isTyping: false,
                   liveDetails: {
                      status: 'disabled',
                      camera: false,
                      mic: false,
                   },
                },
    {
                
                   **isOnline: false,**
                   hasRaisedHand: false,
                   isTyping: false,
                   liveDetails: {
                      status: 'disabled',
                      camera: false,
                      mic: false,
                   },
                },
        ]

Upvotes: 1

Views: 77

Answers (2)

Beshambher Chaukhwan
Beshambher Chaukhwan

Reputation: 1448

Try this code where we sort the data based on a sorting score of elements as per your requirements. Notice that they have a priority based sore i.e., higher the sorting priority criteria, higher the score. The gap between each sorting criteria is kept far apart so that conditions don't overlap. If conditions increase so will we change the score type increments. Check this:

function getScore(a) {
  var n = a.isTyping ? 30 : 0;
  n += a.liveDetails.status == 'active' ? 15 : 0;
  n += a.liveDetails.status == 'pending' ? 14 : 0;
  n += a.hasRaisedHand ? 8 : 0;
  n += a.isOnline ? 2 : 0;
  return n;
}

var results = data.sort((a, b) => getScore(a) < getScore(b));
 
console.log(results);

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386680

You could chain the conditions inside of sort by using an object for sorting various states.

const
    data = [{ isOnline: true, hasRaisedHand: false, isTyping: false, liveDetails: { status: 'pending', camera: false, mic: false } }, { isOnline: true, hasRaisedHand: false, isTyping: false, liveDetails: { status: 'active', camera: false, mic: false } }, { isOnline: false, hasRaisedHand: false, isTyping: false, liveDetails: { status: 'disabled', camera: false, mic: false } }, { isOnline: true, hasRaisedHand: false, isTyping: true, liveDetails: { status: 'disabled', camera: false, mic: false } }, { isOnline: true, hasRaisedHand: true, isTyping: false, liveDetails: { status: 'disabled', camera: false, mic: false } }],
    status = { active: 1, pending: 2, disabled: 3 };

data.sort((a, b) =>
    b.isTyping - a.isTyping ||
    status[a.liveDetails.status] - status[b.liveDetails.status] ||
    b.hasRaisedHand - a.hasRaisedHand ||
    b.isOnline - a.isOnline
);

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

Upvotes: 2

Related Questions