Hommer Smith
Hommer Smith

Reputation: 27852

Sorting array based on multiple conditions in Javascript

I have an array with objects that looks like this:

[{
    id: 34,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'Steven',
        age: 24
    }]
} ,{
    id: 35,
    users: [{
        name: 'John',
        age: 23,
    }, {
        name: 'Steven',
        age: 24
    }, {
        name: 'Charlie',
        age: 24
    }]
}, {
    id: 36,
    users: [{
        name: 'Lisa',
        age: 23,
    }, {
        name: 'John',
        age: 24
    }, {
        name: 'Homer',
        age: 24
    }, {
        name: 'Charlie',
        age: 24
    }]
}, {
    id: 37,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'John',
        age: 24
    }]
}]

I want to order the array based on a couple of conditions (prioritized): First I want the objects that have users with name 'John' AND 'Lisa' and number of users is less than 3 Secondly I want the objects that have users with name 'John' AND 'Lisa' regardless of the number of participants Then the rest of the objects

So, the array that I put as an example, would become:

[{
    id: 37,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'John',
        age: 24
    }]
}, {
    id: 36,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'John',
        age: 24
    }, {
        name: 'Homer',
        age: 24
    }, {
        name: 'Charlie',
        age: 24
    }]
}, {
    id: 34,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'Steven',
        age: 24
    }]
}, {
    id: 35,
    users: [{
        name: 'John',
        age: 23
    }, {
        name: 'Steven',
        age: 24
    }, {
        name: 'Charlie',
        age: 24
    }]
}]

I have this right now, which properly sorts based on the names AND number of participants. But if the number of participants doesn't match, then it doesn't care about the names to sort, which is wrong:

 const names = ['John', 'Lisa']
 unorderedLeagues.sort((a, b) => {
    const aUserIncluded = every(names, priorityName =>
      some(a.users, { name: priorityName }),
    );
    const bUserIncluded = every(names, priorityName =>
      some(b.users, { name: priorityName }),
    );

    return (
      (bUserIncluded && b.users.length <= 3) -
      (aUserIncluded && a.users.length <= 3)
    );
  });

How should I modify this sorting to do the type of priority I described?

Upvotes: 1

Views: 3119

Answers (3)

Jaydip Jadhav
Jaydip Jadhav

Reputation: 12309

Try some thing like this

yourObj.sort(function(curr,next){
    return ((curr.users.filter(x=>x.name=='John'|| x.name=='Steven').length > 0) && curr.users.length < 3 )? 1 : 2;
})

var arrObj= [{
    id: 34,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'Steven',
        age: 24
    }]
} ,{
    id: 35,
    users: [{
        name: 'John',
        age: 23,
    }, {
        name: 'Steven',
        age: 24
    }, {
        name: 'Charlie',
        age: 24
    }]
}, {
    id: 36,
    users: [{
        name: 'Lisa',
        age: 23,
    }, {
        name: 'John',
        age: 24
    }, {
        name: 'Homer',
        age: 24
    }, {
        name: 'Charlie',
        age: 24
    }]
}, {
    id: 37,
    users: [{
        name: 'Lisa',
        age: 23
    }, {
        name: 'John',
        age: 24
    }]
}];


arrObj.sort(function(curr,next){
    return ((curr.users.filter(x=>x.name=='John'|| x.name=='Steven').length > 0) && curr.users.length < 3 )? 1 : 2;
});

console.log(arrObj);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386604

You could use a boolean value for checking if the wanted names are in users. Then take the length as well or not.

var array = [{ id: 34, users: [{ name: 'John', age: 23}, { name: 'Steven', age: 24}] }, { id: 35, users: [{ name: 'John', age: 23}, { name: 'Steven', age: 24}, { name: 'Charlie', age: 24}] }, { id: 36, users: [{ name: 'Lisa', age: 23}, { name: 'John', age: 24}, { name: 'Homer', age: 24}, { name: 'Charlie', age: 24}] }, { id: 37, users: [{ name: 'Lisa', age: 23}, { name: 'John', age: 24}] }],
    find = ['John', 'Lisa'];

array.sort(function (a, b) {
    var aAll = find.every(n => a.users.find(({ name }) => name === n)),
        bAll = find.every(n => b.users.find(({ name }) => name === n));

    return (bAll && b.users.length === 2) - (aAll && a.users.length === 2) || bAll - aAll;
});

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

Upvotes: 2

Sebastian Speitel
Sebastian Speitel

Reputation: 7346

This method should do the job:

var unsorted = [{
    id: 34,
    users: [{
        name: 'Lisa',
        age: 23
      },
      {
        name: 'Steven',
        age: 24
      }
    ]
  },
  {
    id: 35,
    users: [{
        name: 'John',
        age: 23
      },
      {
        name: 'Steven',
        age: 24
      },
      {
        name: 'Charlie',
        age: 24
      }
    ]
  },
  {
    id: 36,
    users: [{
        name: 'Lisa',
        age: 23
      },
      {
        name: 'John',
        age: 24
      },
      {
        name: 'Homer',
        age: 24
      },
      {
        name: 'Charlie',
        age: 24
      }
    ]
  },
  {
    id: 37,
    users: [{
        name: 'Lisa',
        age: 23
      },
      {
        name: 'John',
        age: 24
      }
    ]
  }
];

var sorted = unsorted.sort((a, b) => sortMethod(a, b));
console.log(sorted);

function sortMethod(a, b) {
  var con1a = a.users.find(u => u.name == 'Lisa') && a.users.find(u => u.name == 'John');
  var con1b = b.users.find(u => u.name == 'Lisa') && b.users.find(u => u.name == 'John');

  if (con1a && !con1b) return -1;
  if (!con1a && con1b) return 1;
  return a.users.length - b.users.length;

}

Side note: I had to reformat the invalid JSON first, to get it successfully parsed.

Upvotes: 0

Related Questions