Remove value from js array without reordering keys - javascript

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.

Related

How do I remove all the elements of an array using splice [duplicate]

This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
Is there a way to empty an array and if so possibly with .remove()?
For instance,
A = [1,2,3,4];
How can I empty that?
Ways to clear an existing array A:
Method 1
(this was my original answer to the question)
A = [];
This code will set the variable A to a new empty array. This is perfect if you don't have references to the original array A anywhere else because this actually creates a brand new (empty) array. You should be careful with this method because if you have referenced this array from another variable or property, the original array will remain unchanged. Only use this if you only reference the array by its original variable A.
This is also the fastest solution.
This code sample shows the issue you can encounter when using this method:
var arr1 = ['a','b','c','d','e','f'];
var arr2 = arr1; // Reference arr1 by another variable
arr1 = [];
console.log(arr2); // Output ['a','b','c','d','e','f']
Method 2 (as suggested by Matthew Crumley)
A.length = 0
This will clear the existing array by setting its length to 0. It also works when using "strict mode" in ECMAScript 5 because the length property of an array is a read/write property.
Method 3 (as suggested by Anthony)
A.splice(0,A.length)
Using .splice() will work perfectly, but since the .splice() function will return an array with all the removed items, it will actually return a copy of the original array. Benchmarks suggest that this has no effect on performance whatsoever.
Method 4 (as suggested by tanguy_k)
while(A.length > 0) {
A.pop();
}
This solution is not very succinct, and it is also the slowest solution, contrary to earlier benchmarks referenced in the original answer.
Performance
Of all the methods of clearing an existing array, methods 2 and 3 are very similar in performance and are a lot faster than method 4. See this benchmark.
As pointed out by Diadistis in their answer below, the original benchmarks that were used to determine the performance of the four methods described above were flawed. The original benchmark reused the cleared array so the second iteration was clearing an array that was already empty.
The following benchmark fixes this flaw: http://jsben.ch/#/hyj65. It clearly shows that methods #2 (length property) and #3 (splice) are the fastest (not counting method #1 which doesn't change the original array).
This has been a hot topic and the cause of a lot of controversy. There are actually many correct answers and because this answer has been marked as the accepted answer for a very long time, I will include all of the methods here.
If you need to keep the original array because you have other references to it that should be updated too, you can clear it without creating a new array by setting its length to zero:
A.length = 0;
Here the fastest working implementation while keeping the same array ("mutable"):
function clearArray(array) {
while (array.length > 0) {
array.pop();
}
}
FYI it cannot be simplified to while (array.pop()): the tests will fail.
FYI Map and Set define clear(), it would have seem logical to have clear() for Array too.
TypeScript version:
function clearArray<T>(array: T[]) {
while (array.length > 0) {
array.pop();
}
}
The corresponding tests:
describe('clearArray()', () => {
test('clear regular array', () => {
const array = [1, 2, 3, 4, 5];
clearArray(array);
expect(array.length).toEqual(0);
expect(array[0]).toEqual(undefined);
expect(array[4]).toEqual(undefined);
});
test('clear array that contains undefined and null', () => {
const array = [1, undefined, 3, null, 5];
clearArray(array);
expect(array.length).toEqual(0);
expect(array[0]).toEqual(undefined);
expect(array[4]).toEqual(undefined);
});
});
Here the updated jsPerf: http://jsperf.com/array-destroy/32 http://jsperf.com/array-destroy/152
jsPerf offline. Similar benchmark: https://jsben.ch/hyj65
A more cross-browser friendly and more optimal solution will be to use the splice method to empty the content of the array A as below:
A.splice(0, A.length);
The answers that have no less that 2739 upvotes by now are misleading and incorrect.
The question is: "How do you empty your existing array?" E.g. for A = [1,2,3,4].
Saying "A = [] is the answer" is ignorant and absolutely incorrect. [] == [] is false.
This is because these two arrays are two separate, individual objects, with their own two identities, taking up their own space in the digital world, each on its own.
Let's say your mother asks you to empty the trash can.
You don't bring in a new one as if you've done what you've been asked for.
Instead, you empty the trash can.
You don't replace the filled one with a new empty can, and you don't take the label "A" from the filled can and stick it to the new one as in A = [1,2,3,4]; A = [];
Emptying an array object is the easiest thing ever:
A.length = 0;
This way, the can under "A" is not only empty, but also as clean as new!
Furthermore, you are not required to remove the trash by hand until the can is empty! You were asked to empty the existing one, completely, in one turn, not to pick up the trash until the can gets empty, as in:
while(A.length > 0) {
A.pop();
}
Nor, to put your left hand at the bottom of the trash, holding it with your right at the top to be able to pull its content out as in:
A.splice(0, A.length);
No, you were asked to empty it:
A.length = 0;
This is the only code that correctly empties the contents of a given JavaScript array.
Performance test:
http://jsperf.com/array-clear-methods/3
a = []; // 37% slower
a.length = 0; // 89% slower
a.splice(0, a.length) // 97% slower
while (a.length > 0) {
a.pop();
} // Fastest
You can add this to your JavaScript file to allow your arrays to be "cleared":
Array.prototype.clear = function() {
this.splice(0, this.length);
};
Then you can use it like this:
var list = [1, 2, 3];
list.clear();
Or if you want to be sure you don't destroy something:
if (!Array.prototype.clear) {
Array.prototype.clear = function() {
this.splice(0, this.length);
};
}
Lots of people think you shouldn't modify native objects (like Array), and I'm inclined to agree. Please use caution in deciding how to handle this.
You can easily create a function to do that for you, change the length or even add it to native Array as remove() function for reuse.
Imagine you have this array:
var arr = [1, 2, 3, 4, 5]; //the array
OK, just simply run this:
arr.length = 0; //change the length
and the result is:
[] //result
easy way to empty an array...
Also using loop which is not necessary but just another way to do that:
/* could be arr.pop() or arr.splice(0)
don't need to return as main array get changed */
function remove(arr) {
while(arr.length) {
arr.shift();
}
}
There are also tricky way which you can think about, for example something like this:
arr.splice(0, arr.length); //[]
So if arr has 5 items, it will splice 5 items from 0, which means nothing will remain in the array.
Also other ways like simply reassign the array for example:
arr = []; //[]
If you look at the Array functions, there are many other ways to do this, but the most recommended one could be changing the length.
As I said in the first place, you can also prototype remove() as it's the answer to your question. you can simply choose one of the methods above and prototype it to Array object in JavaScript, something like:
Array.prototype.remove = Array.prototype.remove || function() {
this.splice(0, this.length);
};
and you can simply call it like this to empty any array in your javascript application:
arr.remove(); //[]
If you are using
a = [];
Then you are assigning new array reference to a, if reference in a is already assigned to any other variable, then it will not empty that array too and hence garbage collector will not collect that memory.
For ex.
var a=[1,2,3];
var b=a;
a=[];
console.log(b);// It will print [1,2,3];
or
a.length = 0;
When we specify a.length, we are just resetting boundaries of the array and memory for rest array elements will be connected by garbage collector.
Instead of these two solutions are better.
a.splice(0,a.length)
and
while(a.length > 0) {
a.pop();
}
As per previous answer by kenshou.html, second method is faster.
There is a lot of confusion and misinformation regarding the while;pop/shift performance both in answers and comments. The while/pop solution has (as expected) the worst performance. What's actually happening is that setup runs only once for each sample that runs the snippet in a loop. eg:
var arr = [];
for (var i = 0; i < 100; i++) {
arr.push(Math.random());
}
for (var j = 0; j < 1000; j++) {
while (arr.length > 0) {
arr.pop(); // this executes 100 times, not 100000
}
}
I have created a new test that works correctly :
http://jsperf.com/empty-javascript-array-redux
Warning: even in this version of the test you can't actually see the real difference because cloning the array takes up most of the test time. It still shows that splice is the fastest way to clear the array (not taking [] into consideration because while it is the fastest it's not actually clearing the existing array).
Array.prototype.clear = function() {
this.length = 0;
};
And call it: array.clear();
In case you are interested in the memory allocation, you may compare each approach using something like this jsfiddle in conjunction with chrome dev tools' timeline tab. You will want to use the trash bin icon at the bottom to force a garbage collection after 'clearing' the array. This should give you a more definite answer for the browser of your choice. A lot of answers here are old and I wouldn't rely on them but rather test as in #tanguy_k's answer above.
(for an intro to the aforementioned tab you can check out here)
Stackoverflow forces me to copy the jsfiddle so here it is:
<html>
<script>
var size = 1000*100
window.onload = function() {
document.getElementById("quantifier").value = size
}
function scaffold()
{
console.log("processing Scaffold...");
a = new Array
}
function start()
{
size = document.getElementById("quantifier").value
console.log("Starting... quantifier is " + size);
console.log("starting test")
for (i=0; i<size; i++){
a[i]="something"
}
console.log("done...")
}
function tearDown()
{
console.log("processing teardown");
a.length=0
}
</script>
<body>
<span style="color:green;">Quantifier:</span>
<input id="quantifier" style="color:green;" type="text"></input>
<button onclick="scaffold()">Scaffold</button>
<button onclick="start()">Start</button>
<button onclick="tearDown()">Clean</button>
<br/>
</body>
</html>
And you should take note that it may depend on the type of the array elements, as javascript manages strings differently than other primitive types, not to mention arrays of objects. The type may affect what happens.
Use a modified version of Jan's initial suggestion:
var originalLength = A.length;
for (var i = originalLength; i > 0; i--) {
A.pop();
}
Terser:
for (let i = A.length; i > 0;A.pop(),i--) {}
Or here's another take:
while(!A[Symbol.iterator]().next().done)A.shift()
A.splice(0);
I just did this on some code I am working on. It cleared the array.
If you use constants then you have no choice:
const numbers = [1, 2, 3]
You can not reasign:
numbers = []
You can only truncate:
numbers.length = 0
To Empty a Current memory location of an array use: 'myArray.length = 0' or 'myArray.pop() UN-till its length is 0'
length : You can set the length property to truncate an array at any time. When you extend an array by changing its length property, the number of actual elements increases.
pop() : The pop method removes the last element from an array and returns that returns the removed value.
shift() : The shift method removes the element at the zeroeth index and shifts the values at consecutive indexes down, then returns the removed value.
Example:
var arr = ['77'];
arr.length = 20;
console.log("Increasing : ", arr); // (20) ["77", empty × 19]
arr.length = 12;
console.log("Truncating : ", arr); // (12) ["77", empty × 11]
var mainArr = new Array();
mainArr = ['1', '2', '3', '4'];
var refArr = mainArr;
console.log('Current', mainArr, 'Refered', refArr);
refArr.length = 3;
console.log('Length: ~ Current', mainArr, 'Refered', refArr);
mainArr.push('0');
console.log('Push to the End of Current Array Memory Location \n~ Current', mainArr, 'Refered', refArr);
mainArr.poptill_length(0);
console.log('Empty Array \n~ Current', mainArr, 'Refered', refArr);
Array.prototype.poptill_length = function (e) {
while (this.length) {
if( this.length == e ) break;
console.log('removed last element:', this.pop());
}
};
new Array() | [] Create an Array with new memory location by using Array constructor or array literal.
mainArr = []; // a new empty array is addressed to mainArr.
var arr = new Array('10'); // Array constructor
arr.unshift('1'); // add to the front
arr.push('15'); // add to the end
console.log("After Adding : ", arr); // ["1", "10", "15"]
arr.pop(); // remove from the end
arr.shift(); // remove from the front
console.log("After Removing : ", arr); // ["10"]
var arrLit = ['14', '17'];
console.log("array literal « ", indexedItem( arrLit ) ); // {0,14}{1,17}
function indexedItem( arr ) {
var indexedStr = "";
arr.forEach(function(item, index, array) {
indexedStr += "{"+index+","+item+"}";
console.log(item, index);
});
return indexedStr;
}
slice() : By using slice function we get an shallow copy of elements from the original array, with new memory address, So that any modification on cloneArr will not affect to an actual|original array.
var shallowCopy = mainArr.slice(); // this is how to make a copy
var cloneArr = mainArr.slice(0, 3);
console.log('Main', mainArr, '\tCloned', cloneArr);
cloneArr.length = 0; // Clears current memory location of an array.
console.log('Main', mainArr, '\tCloned', cloneArr);
I'm surprised no one has suggested this yet:
let xs = [1,2,3,4];
for (let i in xs)
delete xs[i];
This yields an array in quite a different state from the other solutions. In a sense, the array has been 'emptied':
xs
=> Array [ <4 empty slots> ]
[...xs]
=> Array [ undefined, undefined, undefined, undefined ]
xs.length
=> 4
xs[0]
=> ReferenceError: reference to undefined property xs[0]
You can produce an equivalent array with [,,,,] or Array(4)

For a deep copy of a JavaScript multidimensional array, going one level deep seems sufficient. Is this reliably true?

Note: I'm only a novice coder, so there might be a glaring error or misconception at the heart of this question.
Essentially, I need to deep copy multidimensional arrays 'by value' in JavaScript to an unknown depth. I thought this would require some complex recursion, but it seems that in JavaScript you only need to copy one level deep in order to copy the whole array by value.
As an example, here is my test code, using a deliberately convoluted array.
function test() {
var arr = [ ['ok1'],[],[ [],[],[ [], [ [ ['ok2'], [] ] ] ] ] ];
var cloned = cloneArray(arr);
arr = ''; // Delete the original
alert ( cloned );
}
function cloneArray(arr) {
// Deep copy arrays. Going one level deep seems to be enough.
var clone = [];
for (i=0; i<arr.length; i++) {
clone.push( arr[i].slice(0) )
}
return clone;
}
In my running of this test (latest stable Chrome and Firefox on Ubuntu), even the deepest parts of the array seem to be successfully copied by value in the clone, even after the original is deleted, despite the fact that the slice() "copying" only went one layer deep. Is this the standard behaviour in JavaScript? Can I depend on this to work for older browsers?
Your test is flawed for whether a true copy is being made which makes your conclusion incorrect that you are getting a full copy of all the data in the nested arrays. You are only doing a two level copy, not an N level copy.
Javascript is a garbage collected language so you don't actually delete variables or objects and, even if you tried that doesn't affect the same variable if it's being referenced somewhere else in your code. To see if you truly have a completely independent copy, try nesting an object two levels deep and then change a property on the object in the original array. You will find that the same object changes in the cloned array because you aren't doing a deep clone. Both arrays have a reference to the exact same object.
Here's an example.
function cloneArray(arr) {
// Deep copy arrays. Going one level deep seems to be enough.
var clone = [];
for (i=0; i<arr.length; i++) {
clone.push( arr[i].slice(0) )
}
return clone;
}
var x = [[{foo: 1}]];
var y = cloneArray(x);
x[0][0].foo = 2;
// now see what the value is in `y`
// if it's 2, then it's been changed and is not a true copy
// both arrays have a reference to the same object
console.log(y[0][0].foo); // logs 2
The same result would happen if the third level was another array too. You will have to recursively traverse every element that is an object type and then clone that object itself to get a complete clone of everything in the nested arrays.
If you want code that will do a deep copy (to an arbitrary level) and work for all data types, see here.
FYI, your cloneArray() function assumes that all first level members of your array are arrays themselves and thus doesn't work if it contains any other type of value.
Array.prototype.slice is not suitable for cloning arrays
This should work well for you
function deepClone(arr) {
var len = arr.length;
var newArr = new Array(len);
for (var i=0; i<len; i++) {
if (Array.isArray(arr[i])) {
newArr[i] = deepClone(arr[i]);
}
else {
newArr[i] = arr[i];
}
}
return newArr;
}
If you need to support older browser, make sure to use this polyfill (via MDN)
if(!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
Your code does not work:
If your array contains other variables such as numbers or strings (not only arrays), it will fail, because it will call arr[i].slice(), but since that arr[i] is a number, it hasn't got any .slice property and this will throw an error.
Your function will, in any case, leave all the references to objects and other stuff inside the array alive. So you will not actually obtain a copy of your array.
Example:
var a = [1,2, [11,13], ['ok']];
var b = cloneArray(a);
> TypeError: undefined is not a function // because numbers have no .slice method
Solution:
To copy an array you will need to make a deep copy of it. Since that creating a deep copy will need a function that uses recursion to deep copy any object or array inside of the main one, the easiest way to do it is by using jQuery and its .extend method, which performs a deep copy of the array, see here for more info.
var a =[[1], [2], [3]];
var b = $.extend(true, [], a);
b[0][0] = 99;
a[0][0] // still 1
Here's my recursive approach to "cloning" a multidimensional array. It runs all the way down to the deepest levels:
if ( !Array.clone )
{
Array.prototype.clone = function()
{
var _arr = ( arguments[0] == null ) ? [] : arguments[0] ;
for( var _p = 0 ; _p < this.length ; _p++ )
{
if ( this[_p] instanceof Array )
{
var _sub = [] ;
this[_p].clone( _sub ) ;
_arr.push( _sub.slice() );
}
else _arr.push( this[_p] );
}
return _arr ;
}
}
Now try this code:
var _a = [ "a", "b", [ "c", "d", [ "e", "f" ] ] ];
var _b = _a.clone();
console.log( _b );
Vars _a and _b are two distinct objects: if you remove an element from var _b, then var _a would not be affected.

How to remove all undefined keys from a javascript array (hopefully when creating the array?)

I have placed my frustrations into a jsfiddle to observe here: http://jsfiddle.net/8ShFr/1/
var brand_new_array = new Array();
brand_new_array[10] = "random array value";
alert('why does this array have a length of ' + brand_new_array.length + '???');
I am doing some calculations client side that require me to set javascript array keys of 1M+ in number.
Not knowing exactly what that number is demands that I iterate through the first 1M+ empty array values before getting to an array key that holds data.
I simply want to set a single large key value for a javascript array without creating a bunch of empty keys before it?
I am using jQuery.each to iterate over the array, and it keeps going through array[0], array[1], array[2], etc... when I only set array[123125] for example.
Just filter out the undefineds.
brand_new_array = brand_new_array.filter(function(n){return n !== undefined});
The reason for the length being 10 is that an array's length is set to the largest index number in the array. However, this does not mean there are 9 other values in there because in javascript an array is at its base an object.
The length is just a property in the object. Arrays in javascript are at their core objects (Array Object 1). They merely act like arrays through an api.
"Whenever a property is added whose name is an array index, the length property is changed, if necessary, to be one more than the numeric value of that array index" 1
1. ECMAScript Language Specification 15.4 Array Objects
You probably want to just use an object with strings for keys (the keys can be the toString() of Numbers, which will happen automatically if you try to use numbers).
var sparse_array_obj = {};
sparse_array_obj[10003210234] = 4; // Fair dice roll
sparse_array_obj[5] = 17; // Truly random number
sparse_array_obj[900] = Math.random(); // Pseudorandom number
for(var i in sparse_array_obj)
console.log(sparse_array_obj[i]);
The downside is that Javascript provides no guarantees about the iteration order through an object (since its keys are unordered by definition). There are however ways around this, such as:
// Sort the keys in numeric order
var sorted_keys = Object.keys(sparse_array_obj).sort(function(a, b){ return a - b; });
for(var i = 0; i < sorted_keys.length; i++)
console.log(sparse_array_obj[sorted_keys[i]]);
Object.keys needs to be shimmed in older browsers.
var brand_new_array = new Array();
brand_new_array[10] = "random array value";
var result = brand_new_array.filter(function(e) { return e != undefined;})[0];
alert(brand_new_array.indexOf(result));
Travis J is right. The array in your example only contains one entry, but your use of jQuery.each() is making you think there are 10 entries because it iterates from 0 up to the highest index number of the array (defines the length). This is from the jQuery.each() API documentation.
A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function's arguments object) are iterated by numeric index, from 0 to length-1. Other objects are iterated via their named properties.
Going back to your example:
var brand_new_array = new Array();
brand_new_array[10] = "random array value";
This will result in only one console.log output:
for(var i in brand_new_array)
console.log(brand_new_array[i]);
This will result in 10 console.log outputs:
$(brand_new_array).each( function(i,e) { console.log(e) })
Similarly, this will result in 10 console.log outputs:
for (var i=0;i<brand_new_array.length;i++)
console.log(brand_new_array[i]);
If you really want to stick with using .each() then you can skip the undefined indices like so:
$(brand_new_array).each( function(i,e) {
if (this.hasOwnProperty(i)){ console.log(e) }
})
Filter the falsy items - including undifined:
var a=[1,2,"b",0,{},"",NaN,3,undefined,null,5];
var b=a.filter(Boolean); // [1,2,"b",{},3,5]
The length is 11 because the index starts at 0.
x[0] = undefined
x[1] = undefined
x[2] = undefined
x[3] = undefined
x[4] = undefined
x[5] = undefined
x[6] = undefined
x[7] = undefined
x[8] = undefined
x[9] = undefined
x[10] = "random array value"

How to check if array of numbers exist in Object

I am trying to write some code that will check to see if a group of numbers stored in an array exist in an object. With the code I have now it is always returning -1.
function checkHorizonal() {
var x= ['1', '2' ,'3'];
var y= ['4', '5', '6'];
var z= ['7', '8', '9']
console.log(jQuery.inArray(x, squaresClicked));
}
This is the squaresClicked object contents:
Object {1: "1", 2: "-1", 3: "1"}
You can see that the keys 1,2,3 exist but it will return -1.
From the jQuery doc:
jQuery.inArray( value, array [, fromIndex ] )
jQuery.inArray won't work the way you're using it. It checks for array contents, not object keys. Your value x is fine, but you're passing in an object instead of an array.
If you're trying to see if a set of integers exists as keys in an object, you can try the following (assuming you're using JavaScript >= 1.6):
myArray.filter(function(x) {
// check if value is a key
return (x in squaresClicked);
}).length == myArray.length;
Basically, we iterate through our array and return only those that exist as keys in the object squaresClicked. If the new array has the same length as our original list, then the values must all exist as properties in the object.
If you don't want to look up an objects entire prototype chain for the array value, you'll need to use hasOwnProperty instead of in.
Like so:
return (squaresClicked.hasOwnProperty(x));
You can read more about this method here.
jQuery's inArray can't deal with an array of needles, otherwise
$.inArray(x, Object.keys(squaresClicked));
would've worked. In this case you are stuck with iterating, I guess (though there might be some other tricky way – as always). One way in jQuery (though I don't very much like it for various reasons1):
var hasFailed = false;
$.each(x, function (index, value) {
if($.inArray(value, Object.keys(squaresClicked)) === -1) {
hasFailed = true;
}
});
return !hasFailed;
A basic vanillaJS approach:
for(var i = 0; i < x.length; i++) {
if(!squaresClicked.hasOwnProperty(x[i])) {
return false;
}
}
return true;
1 Two of the reasons why I dislike it:
It will iterate over the entire array, even if it's already clear that it will fail
It uses a double negation in its logic

How are empty cells stored in a sparse array in JavaScript?

I have a situation where I may be setting an array cell of a high index without setting any of the cells before it.
>>> var arr = [];
undefined
>>> arr[5] = 'value';
"filled"
>>> arr
[undefined, undefined, undefined, undefined, undefined, "filled"]
How is such an array stored in memory? Is there space allocated for each undefined value?
In my actual project, I may be using very large indices. For example, I may set cells 500-800 and 900-1000. I can't use a hash because I need to loop through these non-empty cells and be aware of their index. I want to know if fragmenting the array like this will use up a ton of memory for the empty cells.
Strapping onto aefxx's answer, you can still iterate:
var obj = {500: "foo", 10923: "bar"};
var max = 0;
for (var key in obj)
max=key>max?key:(max||key); // get max key
for (var i=0; i<=max; i++)
console.log(obj[i]); // output even the undefined
As Phrogz commented, it doesn't allocate for undeclared elements of the array. I'm not certain if that's the case if you explicitly set the element value to undefined (e.g. arr[somenum] = undefined;)
I can't use a hash because I need to loop through these non-empty cells and be aware of their index.
What's wrong with the for (x in ...) language construct?
EDITED to accomodate vol7ron's comment:
var x = {2: "foo", 999: "bar"};
for ( var n in x ) {
if ( x.hasOwnProperty(n) ) {
console.log(n);
console.log(x[n]);
}
}
You should probably simply store the max index in a variable and the access your map like this :
for (var i=0; i<=maxIndex; i++) {
console.log(myMap[i]);
}
Then you'll have the (relative) compacity of the map and the ability to loop through unsetted indexes.

Categories