0

Array.prototype.splice() allows to remove multiple elements from array but if and only if theese elements are siblings. But what if no?

Suppose, we need to remove 2th, 5th and 8th elements from array (cont from 0).

const targetArray = [ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india" ];
const indexesOfArrayElementWhichMustBeRemoved = [ 2, 5, 8 ];

for (const [ index, element ] of targetArray.entries()) {

    if (indexesOfArrayElementWhichMustBeRemoved.includes(index)) {
        // remove
    }

}

Once we removed one element, the array will change and 5th element will not be 5th anymore.

Other approach is make elements empty first, and then remove empty elements:

for (const i = 0; i < targetArray.length; i++)  {
    if (indexesOfArrayElementWhichMustBeRemoved.includes(i)) {
        delete targetArray[i]
    }
}


for (const [ index, element ] of targetArray.entries()) {
    if (typeof element === "undefined") {
        targetArray.splice[index, 1]
    }
}

But this methodology does not match with "one pass" requirement and also will delete the element which had "undefined" value initially.

Takeshi Tokugawa YD
  • 670
  • 5
  • 40
  • 124
  • 4
    Loop it backwards – Titus Feb 10 '22 at 13:24
  • 1
    Note that [this answer](https://stackoverflow.com/a/44204227/215552) to the very similar question [Remove all elements contained in another array](https://stackoverflow.com/q/19957348/215552) uses a `Set` to reduce the complexity of lookups. That question and answer use the values at the indexes rather than the indexes themselves though. – Heretic Monkey Feb 10 '22 at 13:51

3 Answers3

1

You could use filter, like this:

const sample = ['a', 'b', 'c', 'd', 'e', 'f']
const idx = [1, 3, 5];
const result = sample.filter((x, i) => idx.includes(i));
console.log(result);

Or if you want to specify which elements to remove, just do !idx.includes(i).

If mutating the original array is a requirement, then the best technique is usually to iterate over the array backwards, and remove as you go. That changing indexes don't matter as much.

for(let i=array.length-1;i>=0;i--){
  // if ... array.splice
}
David784
  • 7,031
  • 2
  • 22
  • 29
1

The usual answer here is to loop backward, or if you have to loop forward, keep track of how many you've removed and adjust the index you're checking accodringly. But, in both cases, you'll still be doing multiple passes through the array, because splice itself is a loop — it has to loop from the index you're deleting at right the way to the end of the array, moving the entries around.

So the other usual answer is: Use filter, which makes a single pass. filter creates a new array, but that's usually just fine.

If you have to modify the original array and you don't want multiple loops (some hidden away inside splice), you can create your own operation instead that copies the elements necessary as it goes, in a single pass:

function removeIndexes(array, indexes) {
    let read = 0;
    let write = 0;
    while (read < array.length) {
        if (!indexesOfArrayElementWhichMustBeRemoved.includes(read)) {
            array[write++] = array[read];
        }
        ++read;
    }
    if (read !== write) {
        // Array got shorter
        array.length = write;
    }
    return array;
}

Live Example:

const targetArray = [ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india" ];
const indexesOfArrayElementWhichMustBeRemoved = [ 2, 5, 8 ];

function removeIndexes(array, indexes) {
    let read = 0;
    let write = 0;
    while (read < array.length) {
        if (!indexesOfArrayElementWhichMustBeRemoved.includes(read)) {
            array[write++] = array[read];
        }
        ++read;
    }
    if (read !== write) {
        // Array got shorter
        array.length = write;
    }
    return array;
}
removeIndexes(targetArray, indexesOfArrayElementWhichMustBeRemoved);

console.log(targetArray);

For completeness, here's going backward:

for (let index = targetArray.length - 1; index >= 0; --index) {
    if (indexesOfArrayElementWhichMustBeRemoved.includes(index)) {
        targetArray.splice(index, 1); // Note that this is an inner loop
    }
}

const targetArray = [ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india" ];
const indexesOfArrayElementWhichMustBeRemoved = [ 2, 5, 8 ];

for (let index = targetArray.length - 1; index >= 0; --index) {
    if (indexesOfArrayElementWhichMustBeRemoved.includes(index)) {
        targetArray.splice(index, 1); // Note that this is an inner loop
    }
}

console.log(targetArray);

and here's keeping track of how many you removed:

let removed = 0;
for (let index = 0; index < targetArray.length; ) {
    if (indexesOfArrayElementWhichMustBeRemoved.includes(index + removed)) {
        targetArray.splice(index, 1); // Note that this is an inner loop
        ++removed;
    } else {
        ++index;
    }
}

const targetArray = [ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india" ];
const indexesOfArrayElementWhichMustBeRemoved = [ 2, 5, 8 ];

let removed = 0;
for (let index = 0; index < targetArray.length; ) {
    if (indexesOfArrayElementWhichMustBeRemoved.includes(index + removed)) {
        targetArray.splice(index, 1); // Note that this is an inner loop
        ++removed;
    } else {
        ++index;
    }
}

console.log(targetArray);

and here's filter:

const replacement = targetArray.filter((_, index) => !indexesOfArrayElementWhichMustBeRemoved.includes(index));

const targetArray = [ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india" ];
const indexesOfArrayElementWhichMustBeRemoved = [ 2, 5, 8 ];

const replacement = targetArray.filter((_, index) => !indexesOfArrayElementWhichMustBeRemoved.includes(index));

console.log(replacement);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

sort indexesOfArrayElementWhichMustBeRemoved desc then loop and splice

const targetArray = [ "alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", "india" ];
const indexesOfArrayElementWhichMustBeRemoved = [ 2, 5, 8 ];

indexesOfArrayElementWhichMustBeRemoved.sort((a,b)=>a<b).forEach((v)=>targetArray.splice(v,1))

console.log(targetArray)
knicholas
  • 520
  • 4
  • 10