0

I have a problem with splice duplicate items in array here is what I have

users=[];

for(let i=0;i<30;i++) users.push({name: 'peter', number:'555'});

users.forEach((element, index, users) => {
  if((element.name === 'peter') && (element.number === '555')){
       users.splice(index, 1);
  }
});

for some reason, it deleting some of them but not all same when I used for loop :/

any suggestions?

sieja
  • 17
  • 4
  • 3
    it is not a good idea to iterate with an array method and mutate the array at the same time. – Nina Scholz Feb 24 '21 at 12:59
  • if you simply need to remove duplicates, try set: `users = [...new Set(users)];` should do the trick – corbin-c Feb 24 '21 at 13:00
  • Does this answer your question? [Looping through array and removing items, without breaking for loop](https://stackoverflow.com/questions/9882284/looping-through-array-and-removing-items-without-breaking-for-loop) – ASDFGerte Feb 24 '21 at 13:00
  • the problem is that `splice` immediately changes the length of your array, so `index` is now pointing at the "wrong" element – Mulan Feb 24 '21 at 13:04
  • 1
    @corbin that's not going to work in this scenario. each object will have a different sharing reference – Mulan Feb 24 '21 at 13:07

3 Answers3

1

You can remove in-place by iterating over the array backwards with a standard for-loop.

const spliceWhere = (arr, predicate) => {
  for (let i = arr.length - 1; i >= 0; i--) {
    if (predicate(arr[i])) {
       arr.splice(i, 1);
    }
  }
  return arr; // Optional, for chaining
}

const users = new Array(30).fill({ name: 'peter', number: '555' });

console.log(JSON.stringify(users));

spliceWhere(
  users,
  ({ name, number }) => name === 'peter' && number === '555'
);

console.log(JSON.stringify(users));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132
1

The go-to solution for most would be to use the built-in method, Array.prototype.filter. This differs from Polywhirl's answer as it constructs a new array and replaces the old one -

let users = [
  {name: 'peter', number:'555'},
  {name: 'alice', number:'555'},
  {name: 'peter', number:'111'},
  {name: 'bobby', number:'555'},
  {name: 'peter', number:'555'},
  {name: 'steve', number:'777'},
  {name: 'peter', number:'555'},
  {name: 'peter', number:'999'},
];

users = users.filter(({ name, number }) => {
  return !(name == "peter" && number == "555")
});

console.log(JSON.stringify(users));
[ 
  {"name":"alice","number":"555"},
  {"name":"peter","number":"111"},
  {"name":"bobby","number":"555"},
  {"name":"steve","number":"777"},
  {"name":"peter","number":"999"}
]

Using De Morgan's Law we can write an equivalent logical expression that may feel more natural for use with filter -

let users = [
  {name: 'peter', number:'555'},
  {name: 'alice', number:'555'},
  {name: 'peter', number:'111'},
  {name: 'bobby', number:'555'},
  {name: 'peter', number:'555'},
  {name: 'steve', number:'777'},
  {name: 'peter', number:'555'},
  {name: 'peter', number:'999'},
];

users = users.filter(({ name, number }) => {
  return name != "peter" || number != "555"  // <- equivalent
});

console.log(JSON.stringify(users));
// []
[ 
  {"name":"alice","number":"555"},
  {"name":"peter","number":"111"},
  {"name":"bobby","number":"555"},
  {"name":"steve","number":"777"},
  {"name":"peter","number":"999"}
]
Mulan
  • 129,518
  • 31
  • 228
  • 259
0

According to MDN documentation, Modifying the array during iteration

forEach() does not make a copy of the array before iterating.

E.g.

let a = [0, 1, 2, 3, 4, 5];
a.forEach((n, I) => {
    console.log(n, I);
    a.shift();
});

Each time before callback() is invoked, the I-nd item of CURRENT a will be acquired. And I will be increased by 1 next time no matter a is changed or not, until it reaches at the end of CURRENT a.

So, you will get:

0 0
2 1
4 2
Youngoat
  • 11
  • 3