Search code examples
javascriptarrayssortingjavascript-objects

How to re-order an array of objects based on several conditions?


I'm trying to use the Array.prototype.sort() method to reorder an array or objects.

My array of objects may look something like (I have removed irrelevant properties from the real life scenario):

[
    {
        context: [
            { value: 'hover' }
        ]
    },
    {
        context: []
    },
    {
        context: [
            { value: 'active' }
        ]
    },
    {
        context: [
            { value: 'large' }
        ]
    }
]

I need to re-order the objects based on the values contained within the nested objects of the context property.

The conditions are:

  • If there are no context objects, move to beginning of array
  • If context object contains a hover value, move to the end of the array

So the above array of 4 objects should be re-ordered from [1, 2, 3, 4] to [2, 3, 4, 1]

I can satisfy the first condition with something like:

rules.sort((a, b) => {
    return (a.context.length - b.context.length);
});

...which re-orders the array based on the number of context objects (thus satisfying the first condition), but I can't figure out how to get the second condition satisfied.

I'm able to determine if either a or b arrays contain a context object with a hover value, which feels like a good start, but I'm not sure where to go from here...

rules.sort((a, b) => {
    const AIsHover  = a.context.some(c => c.value === 'hover');
    const BIsHover  = b.context.some(c => c.value === 'hover');

    return (a.context.length - b.context.length);
});

Any help would be much appreciated! Thanks


Solution

  • You can achieve that simply by distinguishing the cases:

    rules.sort((a, b) => {
        if (!a.context.length && !b.context.length) {
          return 0;
        }
        if (a.context.length && !b.context.length) {
          return 1;
        }
        if (!a.context.length && b.context.length) {
          return -1;
        }
        if (a.context.some(c => c.value === 'hover') && b.context.some(c => c.value === 'hover')) {
          return 0;
        }
        if (a.context.some(c => c.value === 'hover')) {
          return 1;
        }
        if (b.context.some(c => c.value === 'hover')) {
          return -1;
        }
        return 0;
    });