suppose I do..
var arr = Array();
var i = 3333;
arr[i] = "something";
if you do a stringify of this array it will return a string with a whole bunch of undefined numeric entries for those entries whose index is less than 3333...
is there a way to make javascript not do this?
I know that I can use an object {} but I would rather not since I want to do array operations such as shift() etc which are not available for objects
If you create an array per the OP, it only has one member with a property name of "333" and a length of 334 because length is always set to be at least one greater than the highest index. e.g.
var a = new Array(1000);
has a length of 1000 and no members,
var a = [];
var a[999] = 'foo';
has a length of 1000 and one member with a property name of "999".
The speedy way to only get defined members is to use for..in:
function myStringifyArray(a) {
var s = [];
var re = /^\d+$/;
for (var p in a) {
if (a.hasOwnProperty(p) && re.test(p)) {
s.push(a[p]);
}
}
return '' + s;
}
Note that the members may be returned out of order. If that is an issue, you can use a for loop instead, but it will be slower for very sparse arrays:
function myStringifyArray(a) {
var s = [];
var re = /^\d+$/;
for (var i=0, iLen=a.length; i<iLen; i++) {
if (a.hasOwnProperty(i)) {
s.push(a[i]);
}
}
return '' + s;
}
In some older browsers, iterating over the array actually created the missing members, but I don't think that's in issue in modern browsers.
Please test the above thoroughly.
The literal representation of an array has to have all the items of the array, otherwise the 3334th item would not end up at index 3333.
You can replace all undefined values in the array with something else that you want to use as empty items:
for (var i = 0; i < arr.length; i++) {
if (typeof arr[i] == 'undefined') arr[i] = '';
}
Another alternative would be to build your own stringify method, that would create assignments instead of an array literal. I.e. instead of a format like this:
[0,undefined,undefined,undefined,4,undefined,6,7,undefined,9]
your method would create something like:
(function(){
var result = [];
result[0] = 0;
result[4] = 4;
result[6] = 6;
result[7] = 7;
result[9] = 9;
return result;
}())
However, a format like that is of course not compatible with JSON, if that is what you need.
Related
How do I get the number of elements in an array with non-consecutive numbers as keys?
var array = [];
array[5] = "something";
array[10] = "nothing":
expected:
number of elements in array = 2
actual:
instead I get the last number used as the "length", 11
I can figure out the way to do this by iterating through each element. Is there is better way to do this?
You may count non empty cells:
array.filter(function(e){return e!==undefined}).length
Sounds like what you actually want is a dictionary, not an array. Have you considered that as an alternative data structure?
How to do associative array/hashing in JavaScript
var myArray = {};
myArray["5"] = "something";
myArray["10"] = "nothing";
And to get the length you would want to write a quick function like the one shown here:
Length of a JavaScript object
Object.size = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
var size = Object.size(myArray);
Or alternatively, even simpler (but not supported by IE8):
Object.keys(myArray).length
var array = [];
array[5] = "something";
array[10] = "nothing":
Your array in this case becomes :
[undefined,undefined,undefined,undefined,undefined,"something",undefined,undefined,undefined,undefined,"nothing"]
thats why the length is coming as 11. So ideally you should not set it like array[5] or array[10].
If you have variable keys, then you should use object
a = {};
a["5"] = "something";
a["10"] = "nothing"
Then a will look like {"5":"something","10":"nothing"}
Then you can calculate count as :
var elemCount = 0;
for(var key in a){
elemCount++;
}
Output:
elemCount = 2
Various other ways of getting length of keys in object:
How to efficiently count the number of keys/properties of an object in JavaScript?
var array= Array(5);
array[1] = 10;
array[3] = 3;
numberOfElements = 0;
for(var i =0; i<array.length; i++) {
if(array[i]!=undefined)
numberOfElements++;
}
alert(numberOfElements);
I am trying to build an array that should look like this :
[
[{"name":"Mercury","index":0}],
[{"name":"Mercury","index":1},{"name":"Venus","index":1}],
[{"name":"Mercury","index":2},{"name":"Venus","index":2},{"name":"Earth","index":2}],
...
]
Each element is the concatenation of the previous and a new object, and all the indexes get updated to the latest value (e.g. Mercury's index is 0, then 1, etc.).
I have tried to build this array using the following code :
var b = [];
var buffer = [];
var names = ["Mercury","Venus","Earth"]
for (k=0;k<3;k++){
// This array is necessary because with real data there are multiple elements for each k
var a = [{"name":names[k],"index":0}];
buffer = buffer.concat(a);
// This is where the index of all the elements currently in the
// buffer (should) get(s) updated to the current k
for (n=0;n<buffer.length;n++){
buffer[n].index = k;
}
// Add the buffer to the final array
b.push(buffer);
}
console.log(b);
The final array (b) printed out to the console has the right number of objects in each element, but all the indexes everywhere are equal to the last value of k (2).
I don't understand why this is happening, and don't know how to fix it.
This is happening because every object in the inner array is actually the exact same object as the one stored in the previous outer array's entries - you're only storing references to the object, not copies. When you update the index in the object you're updating it everywhere.
To resolve this, you need to create new objects in each inner iteration, or use an object copying function such as ES6's Object.assign, jQuery's $.extend or Underscore's _.clone.
Here's a version that uses the first approach, and also uses two nested .map calls to produce both the inner (variable length) arrays and the outer array:
var names = ["Mercury","Venus","Earth"];
var b = names.map(function(_, index, a) {
return a.slice(0, index + 1).map(function(name) {
return {name: name, index: index};
});
});
or in ES6:
var names = ["Mercury","Venus","Earth"];
var b = names.map((_, index, a) => a.slice(0, index + 1).map(name => ({name, index})));
Try this:
var names = ["Mercury","Venus","Earth"];
var result = [];
for (var i=0; i<names.length; i++){
var _temp = [];
for(var j=0; j<=i; j++){
_temp.push({
name: names[j],
index:i
});
}
result.push(_temp);
}
console.log(result)
try this simple script:
var b = [];
var names = ["Mercury","Venus","Earth"];
for(var pos = 0; pos < names.length; pos++) {
var current = [];
for(var x = 0; x < pos+1; x++) {
current.push({"name": names[x], "index": pos});
}
b.push(current);
}
I have a lot of objects that I'm trying to filter out duplicates from. When an object has a property, IMAGEURL which is present in another object, I want to ignore this object and move on.
I'm using nodeJS for this so if there's a library I can use to make it easier let me know.
I've done similar implementations before with checking string values in arrays, doing something like:
var arr = ['foo', 'bar'];
if(arr.indexOf('foo') == -1){
arr.push('foo')
}
But this won't work for objects, as best I can tell. What are my options here? To put it more simply:
var obj1 = {IMAGEURL: 'http://whatever.com/1'};
var obj2 = {IMAGEURL: 'http://whatever.com/2'};
var obj3 = {IMAGEURL: 'http://whatever.com/1'};
var arr = [obj1, obj2, obj3];
var uniqueArr = [];
for (var i = 0; i<arr.length; i++){
// For all the iterations of 'uniqueArr', if uniqueArr[interation].IMAGEURL == arr[i].IMAGEURL, don't add arr[i] to uniqueArr
}
How can I do this?
You can just use an inner loop (keeping track of whether we've seen the loop by using a seen variable -- you can actually use labels here, but I find the variable method to be easier to read):
for (var i = 0; i<arr.length; i++){
var seen = false;
for(var j = 0; j != uniqueArr.length; ++j) {
if(uniqueArr[j].IMAGEURL == arr[i].IMAGEURL) seen = true;
}
if(!seen) uniqueArr.push(arr[i]);
}
Here is a concise way:
var uniqueArr = arr.filter(function(obj){
if(obj.IMAGEURL in this) return false;
return this[obj.IMAGEURL] = true;
}, {});
http://jsfiddle.net/rneTR/2
Note: this is concise, but orders of magnitude slower than Nirk's answer.
See also: http://monkeyandcrow.com/blog/why_javascripts_filter_is_slow/
I have thousands of legacy code that stores array information in a non array.
For example:
container.object1 = someobject;
container.object2 = someotherobject;
container.object3 = anotherone;
What I want to have is:
container.objects[1], container.objects[2], container.objects[3] etc.
The 'object' part of the name is constant. The number part is the position it should be in the array.
How do I do this?
Assuming that object1, object2, etc... are sequential (like an array), then you can just iterate through the container object and find all the sequential objectN properties that exist and add them to an array and stop the loop when one is missing.
container.objects = []; // init empty array
var i = 1;
while (container["object" + i]) {
container.objects.push(container["object" + i]);
i++;
}
If you want the first item object1 to be in the [1] spot instead of the more typical [0] spot in the array, then you need to put an empty object into the array's zeroth slot to start with since your example doesn't have an object0 item.
container.objects = [{}]; // init array with first item empty as an empty object
var i = 1;
while (container["object" + i]) {
container.objects.push(container["object" + i]);
i++;
}
An alternate way to do this is by using keys.
var unsorted = objectwithobjects;
var keys = Object.keys(unsorted);
var items = [];
for (var j=0; j < keys.length; j++) {
items[j] = unsorted[keys[j]];
}
You can add an if-statement to check if a key contains 'object' and only add an element to your entry in that case (if 'objectwithobjects' contains other keys you don't want).
That is pretty easy:
var c = { objects: [] };
for (var o in container) {
var n = o.match(/^object(\d+)$/);
if (n) c.objects[n[1]] = container[o];
}
Now c is your new container object, where c.object[1] == container.object1
I am coding in javascript & I need HashMap type structure .
Normally when I need hashmaps , I would use associative arrays only (with strings as keys).
But this time I need integers as keys to hashmaps.
So if I try to store A[1000]=obj, 1001 sized array is created & A[1001] is put as obj.
Even if I try A["1000"]=obj , it still allocates 1001 spaces & fills them with undefined.
I dont want that as my keys could be very large ( around 1 mill).
I could use it as A["dummy1000"]=obj but I dont want to use this dirty method.
Anyway of doing it elegantly & with ease too ?
Doing A[1000] = 1 doesn't create an array with 1000 elements. It creates an array object whose length attribute is 1001, but this is only because the length attribute in JavaScript arrays is defined as the maximum index + 1.
The reason it works like this is so you can do for(var i = 0; i < A.length; i++).
I see you're confused about the allocation of the array. To you it looks like JavaScript has filled the elements with undefined - actually there isn't anything there, but if you try to access any element in an array that hasn't been defined you get undefined.
Create a hash code from the key, and use that as index. Make the hash code limited to a small range, so that you get a reasonably small array of buckets.
Something like:
function HashMap() {
// make an array of 256 buckets
this.buckets = [];
for (var i = 0; i < 256; i++) this.buckets.push([]);
}
HashMap.prototype.getHash = function(key) {
return key % 256;
}
HashMap.prototype.getBucket = function(key) {
return this.buckets[this.getHash(key)];
}
HashMap.prototype.getBucketItem = function(bucket, key) {
for (var i = 0; i < bucket.length; i++) {
if (bucket[i].key == key) return i:
}
return -1;
}
HashMap.prototype.setItem = function(key, value) {
var bucket = this.getBucket(key);
var index = this.getBucketItem(bucket, key);
if (index == -1) {
bucket.push({ key: key, value: value });
} else {
bucket[index].value = value;
}
}
HashMap.prototype.getItem = function(key) {
var bucket = this.getBucket(key);
var index = this.getBucketItem(bucket, key);
if (index == -1) {
return null;
} else {
return bucket[index].value;
}
}
Disclaimer: Code is not tested.