0

I have an array of objects. And in each cards object has a property names votedBy, which stores userId of people giving the vote. I want to sort the array by the length of property votedBy. Note: Some object don't have votedBy property.

[{
  id: 'card1',
  text: "Item1",
  votedBy: {
             userId1: true,
             userId2: true
           }
 }, 
 {
  id: 'card2',
  text: 'Item 1',
  votedBy: {
             userId3: true
           }
 }, 
 {
  id: 'card3',
  text: 'Item 3'
 }, 
{
  id: 'card4',
  text: "Item4",
  votedBy: {
             userId5: true,
             userId6: true,
             userId7: true
           }
 }]

I try to use Array.sort like this

array.sort((a,b) => Object.keys(b.votedBy).length - Object.keys(a.votedBy).length )

And it works only if each object has to have a votedBy property. But some of my objects doens't have that property.

The outcome should look like this

[{
     {
      id: 'card4',
      text: "Item4",
      votedBy: {
                 userId5: true,
                 userId6: true,
                 userId7: true
               }
     },
    {
      id: 'card1',
      text: "Item1",
      votedBy: {
                 userId1: true,
                 userId2: true
               }
     }, 
     {
      id: 'card2',
      text: 'Item 1',
      votedBy: {
                 userId3: true
               }
     }, 
     {
      id: 'card3',
      text: 'Item 3'
     }, 
]

Update

array.sort((a, b) => (
  Boolean(b.votedBy) - Boolean(a.votedBy)
  || Object.keys(b.votedBy).length - Object.keys(a.votedBy).length
));

It works only if I have 1 object without sortedBy. If I have more than 1 object without sortedBy, there's an error

Uncaught TypeError: Cannot convert undefined or null to object

new test array should look like that

[{
  id: 'card1',
  text: "Item1",
  votedBy: {
             userId1: true,
             userId2: true
           }
 }, 
 {
  id: 'card2',
  text: 'Item 1',
  votedBy: {
             userId3: true
           }
 }, 
 {
  id: 'card3',
  text: 'Item 3'
 }, 
{
  id: 'card4',
  text: "Item4",
  votedBy: {
             userId5: true,
             userId6: true,
             userId7: true
           }
 },
 {
  id: 'card5',
  text: 'Item 5'
 } ]

Update 2

I manage to make it working by long and ugly code. Does anyone have nicer and shorter code ?

array.sort((a, b) => {
  if (a.votedBy === undefined && b.votedBy === undefined)
  return Boolean(b.votedBy) - Boolean(a.votedBy)
  else if (a.votedBy === undefined) 
  return Object.keys(b.votedBy).length - Boolean(a.votedBy)
  else if (b.votedBy === undefined) 
  return Boolean(b.votedBy) - Object.keys(a.votedBy).length
  else return Object.keys(b.votedBy).length - Object.keys(a.votedBy).length
});

1 Answer 1

2

First sort by whether the difference between the existence of b.votedBy and a.votedBy:

array.sort((a, b) => (
  Boolean(b.votedBy) - Boolean(a.votedBy)
  || (
    a.votedBy &&
    Object.keys(b.votedBy).length - Object.keys(a.votedBy).length
  )
));

const array = [{
    id: 'card1',
    text: "Item1",
    votedBy: {
      userId1: true,
      userId2: true
    }
  },
  {
    id: 'card2',
    text: 'Item 1',
    votedBy: {
      userId3: true
    }
  },
  {
    id: 'card3',
    text: 'Item 3'
  },
  {
    id: 'card4',
    text: "Item4",
    votedBy: {
      userId5: true,
      userId6: true,
      userId7: true
    }
  },
  { id: 'card5', text: 'Item 5' } 
];

array.sort((a, b) => (
  Boolean(b.votedBy) - Boolean(a.votedBy)
  || (
    a.votedBy &&
    Object.keys(b.votedBy).length - Object.keys(a.votedBy).length
  )
));
console.log(array);

A shorter but more inelegant code that creates an unnecessary object would be:

array.sort((a, b) => (
  Object.keys(b.votedBy || {}).length - Object.keys(a.votedBy || {}).length
));

Note that if it's possible for votedBy to have a truthy non-object value, you'll have to be a bit more verbose:

(typeof b.votedBy === 'object') - (typeof a.votedBy === 'object')
Sign up to request clarification or add additional context in comments.

5 Comments

small question, if I add a new object { id: 'card5', text: 'Item 5' } to array. It shows error : Uncaught TypeError: Cannot convert undefined or null to object. So your solution works only if the array has only 1 Object without votedBy ?
the error is caused because your added object doesn't have votedBy property - how should the algorithm behave if such an object is added?
the object without sortedBy should be at the bottom of the result
@tomen Oops, that's right, if there is more than one object without a votedBy property, they'll be sorted against each other, so the Boolean subtraction will evaluate to 0. If you don't care about how the objects without votedBy are sorted with respect to each other, you can just add another check that a.votedBy is truthy before comparing the length of the keys, see edit
Truthly impressive, I've tried hours for a short and clean code like this but still didn't figure it out. Many thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.