简体   繁体   中英

Remove value from js array without reordering keys

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!

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.

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

Update 2018-09-07

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 array

 var 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.

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