Returning an array without a removed element? Using splice() without changing the array?

Viewed 67436

I want to do something like:

var myArray = ["one","two","three"];
document.write(myArray.splice(1,1));
document.write(myArray);

So that it shows first "one,three", and then "one,two,three". I know splice() returns the removed element and changes the array, but is there function to return a new array with the element removed? I tried:

window.mysplice = function(arr,index,howmany){
    arr.splice(index,howmany);
    return arr;   
};

If I try:

var myArray = ["one","two","three"];
document.write(mySplice(myArray,1,1));
document.write(myArray);

It still changes myArray.

14 Answers

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

const oneTwoThree = ['one', 'two', 'three'] // original array

// `filter()` (like most array functions) iterates over every item in the array.
// Whatever returns true here is copied to a new array (the `oneThree` variable).
// `item !== 'two'` returns true for everything except 'two'
const oneThree = oneTwoThree.filter(item => item !== 'two')

console.log(oneTwoThree) // ['one', 'two', 'three'] — the original, unscathed, array
console.log(oneThree) // ['one', 'three'] — a copy of the original, sans the value you wanted to remove

You'd want to do this so you have a non-mutated array.

I don't think performance is as good as something like slice + concat, but worry about that if it becomes a problem (it probably won't unless you're dealing with tens-of-thousands of elements in an array). Until then, filter is really clean.

Also note that this will remove ALL instances of the element two from the array, so make sure you don't have duplicates in your array that might unintentionally get gobbled up by this approach.

You can use the ES6 spread feature:

let myArray = ['one','two','three'];
let mySplicedArray = [...myArray];
mySplicedArray.splice(1,1); 

console.log(myArray); /// ['one', 'two', 'three']
console.log(mySplicedArray); /// ['one', 'three']

I think the best approach to splice an element from array without mutating and without making a copy of itself is using filter:

arr = ["one", "two", "three"]
elToRemove = "two"
filteredArr = arr.filter( n => n != elToRemove)

console.log(arr) // ["one", "two", "three"]
console.log(filteredArr) // ["one", "three"]

If you have the index of the element you want to remove, you can use slice() and spread syntax:

let fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
let removeIndex = 2;
let iHateLemons = [...fruits.slice(0, removeIndex), ...fruits.slice(removeIndex+1)]

// your new array
// console.log(iHateLemons) --> ["Banana", "Orange", "Apple", "Mango"]
// original array still intact
// console.log(fruits) --> ["Banana", "Orange", "Lemon", "Apple", "Mango"]

There's a new tc39 proposal, which adds a toSpliced method to Array that returns a copy of the array and doesn't modify the original.

When this is implemented, the question can be answered with:

const myArray = ["one", "two", "three"];
myArray.toSpliced(1, 1); // => ["one", "three"]
myArray; // => ["one", "two", "three"];

As it's currently in stage 3, it will likely be implemented in browser engines soon, but in the meantime a polyfill is available here or in core-js.

I think the neatest way is to create a simple function, and bind the function to the Array prototype if you need global access.

Most of the answers provided to the question are wrong. People confuse returning one element of one array without modifying its content but what the OP needs is to return a clone of the array without one element.

Here's my solution :

let arr = ['one', 'two', 'three'];

/* functional */
window.cloneSlice = (arr, start, end) => {
  const _arr = arr.slice();
  _arr.splice(start, end);
  return _arr;
}
// usage
console.log(cloneSlice(arr, 1, 1)); // one, three
console.log(arr); // one, two, three

/* prototyped */
Array.prototype.cloneSlice = function (start, end) { return cloneSlice(this, start, end) }
// usage
console.log(arr.cloneSlice(1, 1)); // one, three
console.log(arr); // one, two, three

const getSubArr = (arr, start, end) => {
    return end > start
        ? arr.filter((_, i) => i >= start && i < end)
        : arr.filter((_, i) => i >= start || i < end);
};

This function returns an array which is a sequence of the original array. It's advantage is that it could be used to get a subArray without a sequence located in the middle of the original array.

const chars = ["a", "b", "c", "d", "e", "f"];
console.log(getArrInRange(chars, 2, 4));
console.log(getArrInRange(chars, 4, 2));
document.write(myArray.filter(e => e !== "two"));
document.write(myArray);
Related