Reputation: 53
I have an array, and I want to remove just one element, but without reordering keys. Is there an easy way without using delete or rebuilding the entire array?
Or alternatively clean up after delete to get rid of the undefined values, fixing the length again.
var array = ["valueone", "valuetwo"];
console.dir(array); // keys 0 and 1
array.splice(0, 1);
console.dir(array); // key 1 is now 0, do not want!
Upvotes: 4
Views: 4573
Reputation: 8998
This answer isn't very good, in my opinion. I provided an answer on How do I remove a property from a JavaScript Object that has received much more attention from me over the years and covers this case and goes into much more detail.
The point is, you should be using Array.prototype.splice
and Array.prototype.slice
.
array.splice(start, n)
returns a subset of array
from index start
with n
sequential elements, and removes this subset from the original array, creating a new array in the process.
let array = [1,2,3,4,5,6];
array.splice(2,3); // [3,4,5]
array; // [1,2,6]
array.slice(start, end)
returns a subset of array
from index start
to index end
without mutating the original. The behavior is a little different from splice
, which is why I prefer to call it as array.slice(start, start + n)
.
let array = [1,2,3,4,5,6];
array.slice(2, 2 + 3); // [3,4,5]
array; // [1,2,3,4,5,6]
Of course you could set the index to a sentinel value like null
or ""
, but if you are wanting the array to stay in the same order after a deletion, perhaps you should change your approach--why does "valuetwo"
have to be at index 1? What useful information is even being held in this data structure if the contents are always the same as the keys needed to access them?
The original answer is below. And if I am going to keep the original text, perhaps I should elaborate on why it's bad advice.
You can use javascript's
delete
keyword.delete array[index];
Don't do this. If your array is homogeneous (as it ought to be), then this will corrupt your array by introducing a second type (undefined
). You should use array.splice()
as discussed above, which will create a new array with the specified range omitted.
Unfortunately, this creates an
undefined
index inside of the arrayvar arr = ['pie', 'cake', 'fish']; delete arr[1]; arr; // ['pie', undefined, 'fish']
Case in point.
You could also do this:
var arr = [9,8,7,6]; arr[1] = null; arr; // [9,null,7,6] arr.length; // 4 var i = -1; while(++i < arr.length){ if(arr[i] && typeof(arr[i] === "number")){ alert(arr[i]); } }
You could, but you shouldn't. Not only is this unnecessary, and doesn't do anything useful (because all it's doing is calling alert
), but it's actually broken.
if(arr[i] && typeof(arr[i] === "number")){
alert(arr[i]);
}
You might expect this to only print our element if it is a non-zero number, but will in fact also run for values like "foo"
, []
and document.createElement("p")
, because typeof(arr[i] === "number")
will always return the value "boolean"
, which is a non-empty string, which is truthy and will therefore evaluate true. Which means the only requirement for alert
to be called is that arr[i]
is truthy. There are only six values in the entire language that will cause this if statement to not execute, and those are:
undefined
null
0
""
(pronounced "empty string")false
NaN
Or, if you don't NEED to use arrays, you could use an object and make everything easier:
var obj = { 0: "first", 1: "second", 2: "third" }; delete obj[1]; obj; // {0: "first", 2: "third"} for(var i in obj){ alert(obj[i]); }
Which would instantaneously erase all of the advantages to using an array. Now you have a data set which may or may not be heterogeneous, which can't be filtered, mapped, reduced or transformed in any sane way, and you have to resort to things like for(i in obj)
(which is extremely bug-prone if you dare to use a library like jQuery) to iterate over it. Luckily today we have fancy stuff like Object.keys(obj).map(k => obj[k]).forEach(function(el){ ... })
, but that's no excuse to have bad data structures.
To get the length of an object:
getLength = function(obj){ var i = 0, l = 0; for(i in obj){ l++; } return l; } getLength(obj); // 3
Again, with arrays, this is unnecessary.
But remember that objects sort their indices by
date of creation
, not > by name. This shouldn't result in a road block, though.To sort the indices of an object alphabetically:
sortObject = function (){ var arr = [], i; for(i in this){ arr.push({index:i,content:this[i]}); delete this[i]; } arr.sort(); for(i in arr){ var item = arr[i]; this[item.index] = item.content; } return this; // make chainable } var obj = { acronym: "OOP", definition: "Object-Oriented Programming", article: "http://wikipedia.org/OOP" }; sortObject.apply(obj); // indices are "acronym", "article", "definition"
array.sort(fn)
The whole point of an object is that its properties are unsorted, anyway. Sorting an unsorted list will hardly do anything useful.
Just to illustrate how much better arrays are at doing array things:
let array = ["pie", "cake", "fish", "brownie", "beef", ...];
/* do some stuff... */
array
.filter(el => exclude.indexOf(el) === -1)
.forEach(function(el){
console.log(el);
});
if exclude
is ["cake", "brownie"]
, then this will log the following to the console:
pie
fish
beef
...
Just try to imagine how many unnecessary lines of code it would take to do the same using the approach from the previous version of this answer.
Hope this helped
Hopefully this update helped.
Upvotes: 1
Reputation: 11807
couldn't you just explicitly set the value to undefined or null or an empty string. What are you trying to achieve?
var arr = ['aaaa','bbb','ccc','ddd'];
arr[0]= undefined;
//or
arr[0]= null;
///or
arr[0]= "";
arr.length; <--- 4
Upvotes: 2
Reputation: 339816
You can delete
the elements of an array:
a = ['one', 'two'];
delete a[0];
// a is now [undefined, 'two'];
alternatively, set a[0]
explicitly to undefined
.
Note that an arrays .length
parameter is automatically maintained by the system. If you intentionally set it to a higher number, you'll just get a whole load of undefined
values for the missing keys:
a.length = 10;
// a is now [undefined, 'two', undefined x 8]
If these semantics are not acceptable to you, then you should consider using an Object
instead. This will preserve your keys, and perhaps be more efficient, but you lose the .length
property.
Upvotes: 8