2

I'm trying to figure out how to sort an array of objects by whether or not the value of a property in a nested array of objects contain the value stopped. When that value exists in any nested array of object, I need the parent object to be sorted to the top, from there, I'm trying to secondarily sort that sorted list by id.

const arr = [{
        id: 1,
        things: [{
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
        ],
    },
    {
        id: 2,
        things: [{
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'stopped',
            },
        ],
    },
    {
        id: 3,
        things: [{
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
        ],
    }
]

// desired result
[{
        id: 2,
        things: [{
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'stopped',
            },
        ],
    },
    {
        id: 1,
        things: [{
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
        ],
    },
    {
        id: 3,
        things: [{
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
            {
                thing_id: 1,
                status: 'started',
            },
        ],
    }
]
2
  • 1
    did you try anything yet? Commented Oct 21, 2021 at 19:48
  • 1
    I'm going try returning a new filtered array with objects that have the nested 'stopped' value and sort this array. Then filter the array on objects without that value and sort that array. Finally, concatenate the two arrays. It just seems like there would be a more concise way. Commented Oct 21, 2021 at 19:57

6 Answers 6

1

const checkStopped = (things) => things.some((el) => el.status === 'stopped');

const desired = arr.sort((a, b) => checkStopped(b.things) - checkStopped(a.things));

Sign up to request clarification or add additional context in comments.

1 Comment

a lot of great answers. I'm accepting this one, since it meets my needs and is one of the more concise.
1
arr.sort((a, b) => {
    if (a.things.some(thing => thing.status === "stopped")) {
        return -1;
    } else {
        return a.id - b.id;
    }
});

You simply have to sort, checking that the current object being inspected has at least one "thing" with a status "stopped", otherwise a normal numerical order.

Comments

1
arr.sort((a, b) => {
    const stoppeds_in_a = a.things.map(obj => obj.status).filter(status => status === 'stopped').length
    const stoppeds_in_b = b.things.map(obj => obj.status).filter(status => status === 'stopped').length
    // I want that who has more 'stoppeds' occurrences first
    return stoppeds_in_b - stoppeds_in_a
})

Comments

1

You could introduces a helper function that partitions the collection based on a provided callback. Then concatenate them together to create the desired result.

const arr = [{id:1,things:[{thing_id:1,status:'started'},{thing_id:1,status:'started'}]},{id:2,things:[{thing_id:1,status:'started'},{thing_id:1,status:'started'},{thing_id:1,status:'stopped'}]},{id:3,things:[{thing_id:1,status:'started'},{thing_id:1,status:'started'},{thing_id:1,status:'started'},{thing_id:1,status:'started'}]}];

const [withStopped, withoutStopped] = partition(arr,
  item => item.things.some(item => item.status == "stopped")
);

const result = withStopped.concat(withoutStopped);
console.log(result);

// helper
function partition(iterable, fn) {
  const partitions = { "true": [], "false": [] };
  for (const item of iterable) partitions[!!fn(item)].push(item);
  return [partitions[true], partitions[false]];
}

Comments

1

This is actually a good task for recursion. But if the structure is fixed, I took two loops and one condition. If this is true I made an array push into the global res variable.

const arr = [
    {
        id: 1,
        things: [
            {
                thing_id: 1, 
                status: 'started',
            },
            {
                thing_id: 1, 
                status: 'started',
            },
        ],
    },
    {
        id: 2,
        things: [
            {
                thing_id: 1, 
                status: 'started',
            },
            {
                thing_id: 1, 
                status: 'started',
            },
            {
                thing_id: 1, 
                status: 'stopped',
            },
        ],
    },
    {
        id: 3,
        things: [
            {
                thing_id: 1, 
                status: 'started',
            },
            {
                thing_id: 1, 
                status: 'started',
            },
            {
                thing_id: 1, 
                status: 'started',
            },
            {
                thing_id: 1, 
                status: 'started',
            },
        ],
    }
]

const res = [];

arr.forEach(function(e) {
  let val = Object.values(e.things)  
  val.forEach((t) => {
    if(t.status == "stopped") {
      res.push(e)
    }    
  })
})

console.log('res', res)

Comments

0

you should do something like this

const Firstresult = [];//with stopped
const SecontPartresult = [];//without stopped

arr.forEach(element => {
    element.things.forEach(thing => {
        if (thing.status == "stopped") {
            if (Firstresult.filter(x => x.id == element.id).length == 0) {
                Firstresult.push(element)
            }
        } else if (element.things.filter(x => x.status == "stopped").length === 0) {
            if (SecontPartresult.filter(x => x.id == element.id && x.things !== "stopped").length == 0) {
                SecontPartresult.push(element)
            }
        }

    });

});

SecontPartresult.forEach(element => {
    Firstresult.push(element)
});
console.table(Firstresult)

Comments

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.