0

I have an array of sequences, what i am trying to achieve is whichever last object completed property is true, then the next to next object will have is_to_happen as true

input

const sequences = [
    {
        "title": "Order placed",
        "completed": true
    },
    {
        "title": "To be confirmed",
        "completed": false
    },
    {
        "title": "Approx Thursday product will be shipped",
        "completed": false
    }
]

And this is what i want to have as an expected output

const output = [
    {
        "title": "Order placed",
        "completed": true,
        "is_to_happen": false
    },
    {
        "title": "To be confirmed",
        "completed": false,
        "is_to_happen": false
    },
    {
        "title": "Approx Thursday product will be shipped",
        "completed": false,
        "is_to_happen": true
    }
]

What i have tried so far using array.reduce is not working

sequences.reduce((acc,curr) => {
    acc = [...acc, curr]
    if(curr.completed){
     acc = [...acc, {...curr, is_to_happen: true}]
    }
    return acc     
}, [])
dev
  • 814
  • 10
  • 27

3 Answers3

1

Usea reduce, and also keep track of the index of the completed item:

const sequences = [
    {
        "title": "Order placed",
        "completed": true
    },
    {
        "title": "To be confirmed",
        "completed": false
    },
    {
        "title": "Approx Thursday product will be shipped",
        "completed": false
    },
    { "title": "One more step", "completed": false }
]

const result = sequences.reduce ( (acc,item, i) => {
  if(item.completed) acc.completedIndex = i;
  acc.items.push( {...item,"is_to_happen": (acc.completedIndex != -1) && (i >= acc.completedIndex+2) } );
  return acc;
},{items:[], completedIndex:-1});

console.log(result.items);

Another way to achieve the same is to look backwards 2 elements in the original array for the completed flag

const sequences = [
    {
        "title": "Order placed",
        "completed": true
    },
    {
        "title": "To be confirmed",
        "completed": false
    },
    {
        "title": "Approx Thursday product will be shipped",
        "completed": false
    }
]

const result = sequences.map ( (item, i) => {
  return {...item, is_to_happen: !!sequences[i-2]?.completed};
});

console.log(result);
Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • Just one doubt, if i need to be generic on the above function, assume if the array length increases from 3 to 4, I can see that 4th object having is_to_happen as false. Which is wrong So how can I achieve this ? – dev Nov 23 '21 at 13:55
  • const sequences = [ { "title": "Order placed", "completed": true }, { "title": "To be confirmed", "completed": false }, { "title": "Approx Thursday product will be shipped", "completed": false }, { "title": "One more step", "completed": false } ] const result = sequences.map ( (item, i) => { return {...item, is_to_happen: !!sequences[i-2]?.completed}; }); console.log(result); – dev Nov 23 '21 at 13:57
  • sure let me try it and will update thanks :) – dev Nov 23 '21 at 13:57
  • @dev my mistake that should have been `(i >= acc.completedIndex+2) ` - have updated the first example – Jamiec Nov 23 '21 at 13:59
  • Sure thanks that works, will just check few other test cases around it for making generic. Thanks @ Jamiec – dev Nov 23 '21 at 14:00
  • If you are any chance aware of this https://stackoverflow.com/questions/70063149/event-timeline-with-animation it will be helpful, many thanks in advance – dev Nov 23 '21 at 14:03
1

Here's one approach:

 const todo = [
        {
            "title": "Order placed",
            "completed": true
        },
        {
            "title": "To be confirmed",
            "completed": false
        },
        {
            "title": "Approx Thursday product will be shipped",
            "completed": false
        }
    ]
    
    // find last completed
    var lastCompleted = todo.slice().reverse().find(item => item.completed === true);
    // get the index of the next to the next item.
    var nextToDoIndex = todo.indexOf(lastCompleted) + 2;
    // only change it if it exists.
    if(todo[nextToDoIndex]) todo[nextToDoIndex] = {...todo[nextToDoIndex], is_to_happen: true } 

    console.log(todo)
JBS
  • 639
  • 7
  • 17
  • It will be helpful if it can be generic in this case if the array of sequences gets increased the new object will have is_to_happen as false – dev Nov 23 '21 at 14:04
-1
sequences.reduce((acc, curr) => {
  if (curr.completed)
    acc = [...acc, { ...curr, is_to_happen: true }]
  else
    acc = [...acc, { ...curr, is_to_happen: false }]
  return acc
}, [])

try this.

  • Did you try it? It will not give the output the OP required! – Jamiec Nov 23 '21 at 13:44
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 23 '21 at 13:53