When I'm working with data, I normally have the need of create Arrays or Objects on a loop, let's say "on the fly".
Lets say for example I want to rearrange an array grouping the element by one of the array keys: One of the methods I use is to loop trough an for in. But the problem is when I define more than one index on the fly.
for(key in array){
newArray[array[key]['gouping_key']] = array[key];
}
This example works fine. But if you have more than one element with the same grouping_key, this code is going to override your previous element.
So, I try this:
var i = 0;
for(key in array){
newArray[array[key]['gouping_key']][i] = array[key];
i++
}
But when I add that second index the interpreter complains saying that the newArray[array[key]['gouping_key']] is undefined. Problem it doesn´t seems to have on the previous example.
Why is that?
I've made this fiddle with an example in case the previous snippets an explanation would be insuficient and unclear. In the fiddle you have three snippets (two commented out).
The first one is the error I get when trying something like what Iǘe mentioned previously.
The second is the solution I use.
And the third an example of the creation of an array on the fly with only one index.
Summing up, I want to know why, when you add the second index, you get that error.
Thanks!
var i = 0;
for(key in array){
// If nested object doesn't exist, make an empty one.
newArray[array[key]['gouping_key']][i] =
newArray[array[key]['gouping_key']][i] || [];
newArray[array[key]['gouping_key']][i] = array[key];
i++
}
You need to create an array to push to, it's not created for you. You can use the || operator to only create an empty array if it's undefined.
Also, that's a lot of nesting to follow... If I may...
var x, y;
y = 0;
for(key in array){
x = array[key].gouping_key;
newArray[x][y] = newArray[x][y] || []
newArray[x][y] = array[key];
y++
}
See how much more readable that is? It's also faster! You dont have to deeply traverse complex objects over and over again.
First using for in for arrays is no good idea, it does not what you are expecting I think. see: https://stackoverflow.com/a/4261096/1924298. Using a simple for loop (or while) should solve your problem.
Related
Ok so essentially i have what i think is a JSON object. You see its properties in the picture i provided, now pretty much what i have been trying to do is to write a for each for a particular lvl.
$.each(toSort.items.items.items.items.items, function (index, value) {
console.log(index);
});
So pretty much what i want is a loop nested in the 5th layer, run code. so what i want to know is why is the code above invalid?
Because items is always an array you would have to refer to a certain index within this array. If you want to get one single item you must use the indexes, too.
toSort[0].items[0].items[0] //third level
If you want all values from that arrays you are better off using more than one loop. Moreover for() is much faster than jQuery's each().
for(var i = 0; i < toSort i++){
//first level
for(var j=0; j < toSort[i].items; j++){
//second level
for(var x=0; x < toSort[i].items[j].items; x++){
//third level
}
}
}
Items are arrays in every layer before 5th as well, so to access the items array inside the first layer you need to specify an index, by doing toSort.items.items, the second items is beign accessed as a property, that doesn't exist, to access the second items array inside the first items array you must access it as toSort.items[0].items and so on.
An example of subsequent access might be
toSort.items[0].items[0].items[0].items[0].items[0]
toSort.items[0].items[0].items[0].items[0].items[1]
toSort.items[0].items[0].items[0].items[0].items[2]
...
toSort.items[0].items[0].items[0].items[1].items[0]
toSort.items[0].items[0].items[0].items[1].items[1]
toSort.items[0].items[0].items[0].items[1].items[2]
...
...
...
toSort.items[1].items[1].items[1].items[1].items[0]
toSort.items[1].items[1].items[1].items[1].items[1]
toSort.items[1].items[1].items[1].items[1].items[2]
Looks like it can be used a bit of recursion, isn't it?
I've been teaching myself OOJS by creating a blackjack game. Everything is going great, but since I randomly create cards, sometimes I create and then deal the same card twice in a round. I'm trying to avoid that by writing some logic that gets rid of duplicate cards.
So I found this discussion.
https://stackoverflow.com/a/840849/945517
and the code below:
function eliminateDuplicates(arr) {
var i,
len=arr.length,
out=[],
obj={};
for (i=0;i<len;i++) {
obj[arr[i]]=0;
}
for (i in obj) {
out.push(i);
}
return out;
}
var a=[];
var b=[];
a[0]="fish";
a[1]="fishes";
a[2]="fish";
a[3]="1";
a[4]="fishes";
b=eliminateDuplicates(a);
console.log(a);
console.log(b);
I understand what's going on in general and on almost every line except:
for (i=0;i<len;i++) {
obj[arr[i]]=0;
}
It seems like it's looping through the array and setting the key of obj to zero. What's going on here and how does this help get rid of duplicate entries in the array being passed at the start?
Thanks!
{} = {key: value, key2:value2,....}
The above is essentially a key value map. The code iterates through the array and adds the key into the map with a value of zero. When the map tries to access an existing value, all it does is reset the value to zero. A useless operation, but it avoids an if..else or other more complex logic.
Once the array is done being iterated across, you only need to iterate across the key value map to get the keys. Since the keys are guaranteed to be unique, you have a list of unique items.
The main thing to realize here is that an object can only have one property per unique string, so when you set obj.fish to 0 when i = 0, you don't add a second "fish" property to obj when i = 2.
Then you can just loop through all of the properties of obj, each one is guaranteed to be unique, and thus you have stripped duplicates.
I have some simple Javascript looping through an array of items (Tridion User Groups) to check if the user is a member of a specific group.
I can easily code around the issue shown below ( see && extensionGroup !== 'true') but I want to understand why the isArray = true is counted as a value in the array - any ideas?
The screenshot below demonstrates that the value extensionGroups has been set thus
var extensionGroups = ["NotEvenARealGroup", "Author", "ExampleGroupAfterOneUserIsActuallyIn"];
but returns the isArray value as a 4th value?
updated to show images a little clearer
You're using for in to iterate an array; don't do that. Use for (or forEach):
for(var i = 0; i < extensionGroups.length; i++) {
var extensionGroup = extensionGroups[i];
// ...
}
The reason this fails is because for in is used to iterate over an object's properties in JavaScript. Iterating over an array in this way means you get anything else assigned to it, such as this property or length.
And if you're able to use Array#forEach, it's probably most appropriate here:
extensionGroups.forEach(function(extensionGroup) {
// ...
});
For..in, technically speaking, doesn't iterate through values. It iterates through property names. In an array, the values ARE properties, under the hood. So when you iterate over them with for..in you get funky stuff like that happening.
Which highlights my next point: don't use for..in. Don't use it for arrays -- don't use it for anything, really. Ok -- maybe that's going a bit too far. How about this: if you feel the need to use for..in, think hard to see if it's justifiable before you do it.
I hope you can help me with this hopefully stupid problem.
I try to do the following:
creating array with data
looping through this array within a for loop (based on array.length)
create new object based on data in array
So far I got the following:
create array
loop through array
create one object based on my constructor
The problem is, the array has a length of 4 and should therefore create 4 objects but it creates only one. If I remove the creation of the object and just log "i' it works, but in the original intention it ends after the first
The loop looks as follows:
for(i=0;i<array.length;i++)
{
newObj[i]=new ObjectName(array[i].param1,array[i].param2,array[i].param3)
}
I have no idea why it ends after the first run and I also don't get an error displayed when looking into firebug.
Cheers
Does changing the
newObj[i] =
to
newObj.push(...)
help?
Also how is newObj initialized?
newObj = []
for (i = 0; i < (stringNums.length); i++) {
Dictionary[stringNums[i]] = stringNums[i].length;
}
My JS-code has array arrayResults, some element of him can be "undefined" - this is feature of algorithm. To check that there is no such elements I use the follow code:
for (i in arrayResults)
{
if (typeof(arrayResults[i])=='undefined')
{
// ask user to repeat
};
};
But, using the debugger, I found that JS-engine passes the "undefined"-item of array (in for condition), respectively I don't have the possibility to make the comparing and make the follow instructions.
So, is there any way to really check the "undefined" items in array? (I can't to set items of array in sequence, because if I found the position of "undefined" item, I tell to user to go to this position).
Don't use a for..in loop to iterate arrays. If you are interested in the reasons, please read this StackOverflow question. They should only be used for traversing objects.
Use a simple oldschool for loop instead, it will solve your problem.
for (var i = 0, l = arrayResults.length; i < l; i++) {
if (typeof(arrayResults[i])=='undefined') {
// ask user to repeat
};
};
jsFiddle Demo
You can use indexOf method on array.
function hasUndefined(a) {
return a.indexOf() !== -1;
}
hasUndefined([1,2,3, undefined, 5]);