how to update next elements value based on the previous one

I have following sample array

let myArray = [
  {name: "Sam", status: 'not_started', progress: 'start'},
  {name: "Sara", status: 'not_started', progress: 'start'},
  {name: "John", status: 'not_started', progress: 'start'},
  {name: "Eric", status: 'not_started', progress: 'start'}
]

If all elements are having status: 'not_started' then I want to update first one's progress to 'start' and the rest as 'lock'. so the array would look like this:

let myArray = [
  {name: "Sam", status: 'not_started', progress: 'start'},
  {name: "Sara", status: 'not_started', progress: 'lock'},
  {name: "John", status: 'not_started', progress: 'lock'},
  {name: "Eric", status: 'not_started', progress: 'lock'}
]

if first element has status 'completed' then second one will have 'start' and rest will have 'lock' like below

let myArray = [
  {name: "Sam", status: 'completed', progress: 'completed'},
  {name: "Sara", status: 'not_started', progress: 'start'},
  {name: "John", status: 'not_started', progress: 'lock'},
  {name: "Eric", status: 'not_started', progress: 'lock'}
]

Also if first two are 'completed' then it'd look like below

let myArray = [
  {name: "Sam", status: 'completed', progress: 'completed'},
  {name: "Sara", status: 'completed', progress: 'completed'},
  {name: "John", status: 'not_started', progress: 'start'},
  {name: "Eric", status: 'not_started', progress: 'lock'}
]

I tried to map over myArray and creating an array of status and progress values and get progress value based on status progress: array[status] but that would not update the progress for progress: 'lock' correctly since 'not_started' can have progress: 'start' or 'lock'

Clearly i need to update the next one based on previous one's value but quite not getting that.

Does anyone know how can i achieve this?

Thanks

javascript

Answers

answered 2 months ago Nenad Vracar #1

You could use map() method and on first occurrence of not_started status you can set this.started to true and based on that change progress to lock.

let myArray = [
  {name: "Sam", status: 'completed', progress: 'start'},
  {name: "Sara", status: 'not_started', progress: 'start'},
  {name: "John", status: 'not_started', progress: 'start'},
  {name: "Eric", status: 'not_started', progress: 'start'}
]
  
const result = myArray.map(function(e) {
  if(e.status == 'completed') return {...e, progress: 'completed'}
  if (this.started) return { ...e, progress: 'lock'}
  if (e.status == 'not_started') this.started = true;
  return { ...e};
}, {});

console.log(result)

answered 2 months ago SteepZero #2

Is that what you needed? I hope I understood you correctly https://jsfiddle.net/txn1cb2z/

    function iterate(arr) {

    let started_key = -1;

    for( let index in arr){
        if(arr[index].status === 'completed') {
            arr[index].progress = 'completed';
            continue;
        }

        if(arr[index].status === 'not_started'){
            arr[index].progress = 'start';
            started_key = parseInt(index);
            break;
        }
    }

    if(started_key < 0 || started_key >= arr.length -1)
        return;

    for (let i = started_key+1; i < arr.length; i++){
        arr[i].progress = 'lock';
    }

    return started_key;
}

function log(arr) {
    for (var index in arr) {
        console.log(index,arr[index].status,arr[index].progress);
    }
    console.log('------------');
}

let myArray = [
    {name: "Sam", status: 'not_started', progress: 'start'},
    {name: "Sara", status: 'not_started', progress: 'start'},
    {name: "John", status: 'not_started', progress: 'start'},
    {name: "Eric", status: 'not_started', progress: 'start'}
];

iterate(myArray);
log(myArray);

myArray[0].status = 'completed';
iterate(myArray);
log(myArray);

myArray[1].status = 'completed';
iterate(myArray);
log(myArray);

myArray[2].status = 'completed';
iterate(myArray);
log(myArray);

myArray[3].status = 'completed';
iterate(myArray);
log(myArray);

answered 2 months ago HMR #3

Your requirements don't make any sense since step 1 is:

If all elements are having status: 'not_started' then I want to update first one's progress to 'start' and the rest as 'lock'. so the array would look like this:

Notice that all of the status fields of the items are still 'not_started' so calling a function to start next will still just set all progress to 'lock' except the first one.

If step 1 would be: all items have a status of "not_started" and the second item has a progress of "lock" then you can actually implement the rest as you describe.

const myArray = [
  {name: "Sam", status: 'not_started', progress: 'start'},
  {name: "Sara", status: 'not_started', progress: 'start'},
  {name: "John", status: 'not_started', progress: 'start'},
  {name: "Eric", status: 'not_started', progress: 'start'}
]

const isAllNotStarted = arr =>
  arr.reduce((allNotStarted,item)=>(item.status==="not_started"&&allNotStarted),true);


const startNext = arr => {
  var status = "";
  if(isAllNotStarted(arr)&&arr[1].progress!=="lock"){
    arr = arr.map(item=>({...item,progress:"lock"}));
    arr[0].progress="start";
    status = "continue";
  }
  return arr
  .reduce(
    ([result,status],current)=>{
      if(current.progress==="start" && current.status==="not_started" && status===""){
        return [result.concat({...current,progress:"completed",status:"completed"}),"startNext"];
      }
      if(current.progress==="lock" && current.status==="not_started" && status==="startNext"){
        return [result.concat({...current,progress:"start"}),"continue"];
      }
      return [result.concat(current),status];
    },
    [[],status]
  )[0]
}

["first","next","next","start last","complete last","run over (do nothing but copy the array)"]
.reduce(
  (arr,item)=>{
    console.log(item);
    const next = startNext(arr);
    console.log(next);
    return next;
  },
  myArray
);

comments powered by Disqus