Toivo Säwén
Toivo Säwén

Reputation: 2042

Modify array in place while using .filter and .forEach

I would like to filter an array of objects and update some value on the filtered entries. Here is my original code, without filtering:

let obj = {
  foo: [
    {
      bar: "I should be modified",
      modify: true,
    },{
      bar: "I should not be modified",
      modify: false,
    },{
      bar: "I should be modified",
      modify: true,
    },
  ],
};

obj.foo.forEach((item, i) => {
  let newItem = Object.assign({}, item);
  newItem.bar = "I have been modified";
  obj.foo[i] = newItem;
});

console.log(obj.foo);
/* Output:
  [
    {
      bar: "I have been modified",
      modify: true,
    },{
      bar: "I have been modified",
      modify: false,
    },{
      bar: "I have been modified",
      modify: true,
    },
  ],
*/

Now I would like to replace .forEach(... with .filter(e => e.modify).forEach(.... So instead of modifying all the elements of obj.foo, only those with modify === true are modified. How can this be done without filtering again inside the forEach loop?

obj.foo.filter(e => e.modify).forEach((item, i) => {
  let newItem = Object.assign({}, item);
  newItem.bar = "I have been modified";
  obj.foo[i] = newItem; // will not work as the index i is not correct from the original array
});

console.log(obj.foo);

/* Expected output:
  [
    {
      bar: "I have been modified",
      modify: true,
    },{
      bar: "I should not be modified",
      modify: false,
    },{
      bar: "I have been modified",
      modify: true,
    },
  ],
*/

/* Actual output:
  [
    {
      bar: "I have been modified",
      modify: true,
    },{
      bar: "I have been modified",
      modify: true,
    },{
      bar: "I should be modified",
      modify: true,
    },
  ],
*/

Upvotes: 1

Views: 1291

Answers (3)

Qiu Zhou
Qiu Zhou

Reputation: 1275

So after read all the comments, that you don't want if-statement in it and other things, then this idea comes to my mind, without changing too much of your code, why don't let each item takes it's own original index, after modified, delete the idx property:

let obj = {
  foo: [
    {
      bar: "I should be modified",
      modify: true,
    },{
      bar: "I should not be modified",
      modify: false,
    },{
      bar: "I should be modified",
      modify: true,
    },
  ],
};
let index = 0;

obj.foo.filter(e =>  ++index && e.modify && (e.idx = index)).forEach((item, i) => {
  let newItem = Object.assign({}, item);
  newItem.bar = "I have been modified";
  obj.foo[newItem.idx - 1] = newItem; 
  delete newItem.idx;
});

console.log(obj.foo);

Upvotes: 0

Swapnil Thakre
Swapnil Thakre

Reputation: 1

This can also be done like this:

obj.foo.filter(e => e.modify).map((item) => {
  item.bar = "I have been modified"
});

I think this should help.

Upvotes: 0

Gorynych
Gorynych

Reputation: 100

let obj = {
  foo: [
    {
      bar: "baz",
      modify: true,
    },{
      bar: "bad",
      modify: false,
    },{
      bar: "hello",
      modify: true,
    },
  ],
};

const {foo} = obj;

const t = foo.reduce((acc, curr) => {
  if (curr.modify) {
    curr.bar = "I have been modified";
    acc.push(curr);
  }
  return acc;
}, []);

console.log(t)

Upvotes: 1

Related Questions