简体   繁体   中英

.splice() removes item from two arrays - delete duplicates from array

I want to remove duplicates from an array, so I wrote code with two for loops.

 let MainArray = [{ "name": "banana", "lat": 3, "lng": 3 }, { "name": "apple", "lat": 3, "lng": 3 }, { "name": "car", "lat": 1, "lng": 1 }, { "name": "bike", "lat": 1, "lng": 1 } ]; let ArrayCopy = MainArray; console.log(MainArray.length); console.log(ArrayCopy.length); for (let i = 0; i < MainArray.length; i++) { for (let x = 0; x < ArrayCopy.length; x++) { if ((MainArray[i].name !== ArrayCopy[x].name) && ((MainArray[i].lat === ArrayCopy[x].lat) || (MainArray[i].lng === ArrayCopy[x].lng))) { //some output ArrayCopy.splice(x, 1); } } } console.log(MainArray.length); console.log(ArrayCopy.length);

I want to avoid, that the results match twice. For example:

result 1: banana & apple

result 2: apple & banana

That's why I want top splice the match from ArrayCopy.

Before the loop starts the length of MainArray and ArrayCopy are both 4, but after the loop both arrays length are 2.

Why does the length of MainArray change?

The second array is the same object as the original array. To copy the array, you need to create a new array, and append the new array with the items from the first array.Below we use the spread operator to fill a new array with all the values from the main array.

 let MainArray = [{ "name": "banana", "lat": 3, "lng": 3 }, { "name": "apple", "lat": 3, "lng": 3 }, { "name": "car", "lat": 1, "lng": 1 }, { "name": "bike", "lat": 1, "lng": 1 } ]; let ArrayCopy = [...MainArray]; console.log(MainArray.length); console.log(ArrayCopy.length); for (let i = 0; i < MainArray.length; i++) { for (let x = 0; x < ArrayCopy.length; x++) { if ((MainArray[i].name !== ArrayCopy[x].name) && ((MainArray[i].lat === ArrayCopy[x].lat) || (MainArray[i].lng === ArrayCopy[x].lng))) { //some output ArrayCopy.splice(x, 1); } } } console.log(MainArray.length); console.log(ArrayCopy.length);

You can also use the slice method to return an array of all the items by not passing any parameters.

const clone = originalArray.slice()

arrays are passed by reference. Which means if you change the copy, the original will change as well. if you want a clone of your original array, do this:

 let MainArray = [{ "name": "banana", "lat": 3, "lng": 3 }, { "name": "apple", "lat": 3, "lng": 3 }, { "name": "car", "lat": 1, "lng": 1 }, { "name": "bike", "lat": 1, "lng": 1 } ]; let ArrayCopy = JSON.parse(JSON.stringify(MainArray)); console.log(MainArray.length); console.log(ArrayCopy.length); for (let i = 0; i < MainArray.length; i++) { for (let x = 0; x < ArrayCopy.length; x++) { if ((MainArray[i].name !== ArrayCopy[x].name) && ((MainArray[i].lat === ArrayCopy[x].lat) || (MainArray[i].lng === ArrayCopy[x].lng))) { //some output ArrayCopy.splice(x, 1); } } } console.log(MainArray.length); console.log(ArrayCopy.length);

The reason this happens is that you are actually storing the first array in the second variable, so you aren't storing another array in there but a reference to the value of the first variable if that makes sense.

 let MainArray = [{ "name": "banana", "lat": 3, "lng": 3 }, { "name": "apple", "lat": 3, "lng": 3 }, { "name": "car", "lat": 1, "lng": 1 }, { "name": "bike", "lat": 1, "lng": 1 } ]; let ArrayCopy = [] MainArray.forEach((item) => { ArrayCopy.push(item) }) console.log(MainArray.length); console.log(ArrayCopy.length); for (let i = 0; i < MainArray.length; i++) { for (let x = 0; x < ArrayCopy.length; x++) { if ((MainArray[i].name !== ArrayCopy[x].name) && ((MainArray[i].lat === ArrayCopy[x].lat) || (MainArray[i].lng === ArrayCopy[x].lng))) { //some output ArrayCopy.splice(x, 1); } } } console.log(MainArray.length); console.log(ArrayCopy.length);

Currenty, ArrayCopy references the same memory as MainArray . As a result, changing ArrayCopy also changes MainArray (since they refer to the same thing). This is typically referred to as "pointer aliasing", and is often the source of tricky bugs (as you've discovered).

Here's an analogy that might help: if Jones has a brother named Steve, then "Jones' brother" and "Steve" both refer to the same person, even though they're different phrases. If you deposit $100 into "Steve's" bank account, you've also just deposited $100 into "Jones' brother's" bank account (because they're the same person).

In general, it's much easier to use functions that don't mutate their arguments. Here's a version of removeDuplicates that produces a new array. The strategy is fairly similar to the one you've used above, except it allocates and returns a new array:

function removeDuplicates(xs) {
  // This is a newly allocated array, which we'll fill with the unique elements from `xs`:
  const unique = [];

  for (let x of xs) {
    if (unique.find(y => y.name === x.name && y.lat === x.lat && y.lng === x.lng)) {
      // If we've already seen an element that's equal to `x`, continue.
      continue;
    } else {
      // Otherwise, add it to the output array.
      unique.push(x);
    }
  }

  return unique;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM