Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mutate array with carried function?

I have an array of objects I want to update with a new value that is dependent on the sequence.

So this:

[
  { "init": 3, "data": "..." },
  { "init": 3, "data": "..." },
  { "init": 3, "data": "..." },
  { "init": 5, "data": "..." },
  { "init": 6, "data": "..." },
  { "init": 6, "data": "..." },
  { "init": 7, "data": "..." },
  { "init": 8, "data": "..." }
  }
]

.. becomes this:

[
  { "init": 3, "group": "odd",  "data": "..." },
  { "init": 3, "group": "odd",  "data": "..." },
  { "init": 3, "group": "odd",  "data": "..." },
  { "init": 5, "group": "even", "data": "..." },
  { "init": 6, "group": "odd",  "data": "..." },
  { "init": 6, "group": "odd",  "data": "..." },
  { "init": 6, "group": "odd",  "data": "..." },
  { "init": 7, "group": "even", "data": "..." },
  { "init": 8, "group": "odd",  "data": "..." }
  }
]

That is, into each item insert a "group" element that according to whether it is in an even-most or odd-most group of "init" values.

The array is always sorted ascending by the "init" value".

NB. "odd" or "even" is not determined from the oddness/evenness of the "init" value, but the oddness/evenness of the group that init value falls into. In this example the first group of init values is "3", and so all items with "init":"3" is marked "odd". The second group would be an "even" group, and thus marked "even".

like image 810
Erics Avatar asked Jan 27 '23 03:01

Erics


2 Answers

It's not used very often, but the functions like map and forEach take an optional final argumnet to be used as this in the callback. You can take advantage of this to maintain state while proceeding through the loop.

For example:

let a = [
    { "init": 3 },
    { "init": 3 },
    { "init": 3 },
    { "init": 5 },
    { "init": 6 },
    { "init": 6 },
    { "init": 7 },
    { "init": 8 }
  ]

let res = a.map(function({init}) {
    if (this.last !== init) this.even = !this.even
    this.last = init
    return {init, group:this.even ? "even": "odd" }
}, {last: undefined, even:true} )

console.log(res)

One note of caution: because it's depending on this, you can't use an arrow function for the callback.

like image 85
Mark Avatar answered Feb 05 '23 10:02

Mark


All you need is a for loop:

  let prev, odd =  false;
   for(const el of data) {
     if(prev !== el.init) odd = !odd;
     el.group = odd ? "odd" : "even";
     prev = el.init;
   }
like image 33
Jonas Wilms Avatar answered Feb 05 '23 11:02

Jonas Wilms