running a for each loop for nested json - javascript

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?

Related

Why is this for loop not removing all repetitions of arrays?

Backset is an array of arrays, I am trying to filter out any arrays which contain a repetition of elements, such as an array with 2 ones. I would like to remove these from the Backset array.
However this is not happening and some arrays in backSet such as [1,2,2] stay in backSet.
for(z=0; z<backSet.length; z++){
backSet[z].sort();
tempBackSort = [];
for(k=0; k< backSet[count].length; k++){
if(tempBackSort.includes(backSet[count][k])){
backSet.splice(backSet.indexOf(backSet[count]),1);
kon = 0;
continue;
} else{
tempBackSort.push(backSet[count][k]);
kon = 1;
}
}
if(kon===1){
count++;
}
backSet[z].sort();
}
There are several issues:
Where you have continue now it accomplishes nothing. You need break, so the inner loop is exited
You try to overcome the problem of iterating over an array where elements are sometimes removed by using count, but:
count is not initialised
You still have code that works with backSet[z] instead of backSet[count]
It would have been easier to just decrease z when an element is removed, or even better: to let the outer loop iterate backwards from end to start -- then you don't need to adjust any index.
Variables are implicitly declared as globals: this is bad practice. Define your variables with let or const.
By sorting the inner arrays, you mutate the original data. This might be OK for your case, but still it is maybe surprising for code that depends on this piece of code.
Sorting is also not the most efficient way to find duplicates. Instead of pushing values in tempBackSort, put them in a Set (which cannot contain duplicates) and compare its size with the original array: if their sizes are not the same, then there are duplicates.
Instead of splicing inside a loop (which is the cause of your trouble), use the array method filter which returns the filtered array.
Here is how it could be coded:
backSet = backSet.filter(arr => (new Set(arr)).size == arr.length);

How we can display two ng-repeat alternately one by one

I have two ng-repeat i want to display them in the grid one by one alternately from both of the tr's. Like first index of first tr then first index of 2nd tr. If any help really appreciable. Thanks in advance.
Create a function to weave your two arrays together. Something like this:
function combine(arr1, arr2){
var result = [];
for(var i=0; i < arr1.length; i++){
result.push(arr1[i]);
result.push(arr2[i]);
}
return result;
}
(this is a simple example, and doesn't account for the arrays being different sizes.)
Then you can assign a $scope variable to the result of this function, and use that variable in the ng-repeat.
Demo
Create in the scope an array containing the stuff from your 2 initial arrays and then you'll be able to ng-repeat the big array containing all your elements in the right order.

Create nested arrays on a loop in Javascript

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.

Looping through Array and assigning values to variables

I haven't got any code yet, as I was just wondering if it is possible to loop through an Array that is dynamically populated to the amount of values could be different each time. The variables would obviously have to make use of an incrementing value?
You can use the array length property to work with an unknown array lengths:
var arr = ["carrots", "bananas", "onions"];
for (var i = 0, len = arr.length; i < len; i++) {
//every element accesible via arr[i];
//example:
console.log(arr[i]);
}
That will loop through the whole array even if it there are more or less elements on it
With this base, I am sure you can do what you want from here
I'm sure by now you've probably figured it out, but I'll just add this here for any future Javascript beginners.
Javascript Arrays have a built-in function called forEach allowing you to iterate over every element in an array. It functions as a loop specifically meant for Arrays. It takes a callback function as an argument and looks like the following:
let stringArr = ['dog', 'cat', 'lion', 'elephant'];
stringArr.forEach(function(element, counter) {
console.log(counter+') '+element);
});
// Outputs:
0) dog
1) cat
2) lion
3) elephant
The callback function can, of course be replaced by an arrow function, if you'd like, but as you can see the first argument in the callback function (element) is the element in the array, and the second argument (counter) keeps track of the index of the element in the array.
What I love about the forEach is that it makes accessing the array elements easier (even if only somewhat) than using a standard for-loop. For instance when looping through objects with a for-loop, to access the individual elements in the array one would have to do myArray[i].property, but using the forEach, one can simply do element.property.
Here's some additional reading on the forEach if it still hasn't quite clicked yet.

How to nest loops to cycle through indexed array inside of associative array (JS)

I've got an indexed array of urls nested inside of another array that uses strings as its keys. I need to extract information from both arrays and I'm using the following loops.
// Loop through the elements in the associative level to get a count of its items
var keyCnt = 0;
for(key in serviceCategories) {
keyCnt++;
}
// Then loop through it again, this time nesting another for loop to get at the inner/indexed arrays
for(key in serviceCategories) {
var currCat = key;
for (var i = 0; i < keyCnt; i++) {
$.ajax({
url: serviceCategories[currCat][i],
success: function(data) {
parsePageCont (data, currCat);
}
});
}
}
}
This code works ok for the first element of the first array. It cycles through its inner array and excecutes the ajax call for every url with no problem. But then, when it finishes with the first element of the first array it doesn't proceed to the second one and fetch IT'S inner array data.
I hope that explanation wasnt too messed up.
You can see the full code here for more clarity: http://jsfiddle.net/FvP5f/
Assuming your data structure is an object with arrays for properties, you would do it like this.
serviceCategories has to be an object, not an array. Javascript doesn't have associative arrays. It has objects for storage by key and iteration by key. Arrays indexes are numeric.
You have to actually iterate over the length of each embedded array.
You can't refer to the key variable in the success handler because that gets called long after the loops so it's value has changed. To solve that problem, we put the key in a context object that will get set as the "this" pointer for the success handler so we can get back to the key.
Here's the code to solve those issues:
// assume data is of this structure (where I've shown numbers here, they are actually URLs)
serviceCategories = {
houses: [1,2,3,4],
cottages: [5,6,7,8],
hotels: [8,9,0,1],
apartments: [2,2,3,4,5,7,8,9]
};
for (key in serviceCategories) {
if (serviceCategories.hasOwnProperty(key)) {
var array = serviceCategories[key];
// got the next array, iterate through it
for (var i = 0; i < array.length; i++) {
var context = {};
$.ajax({
url: array[i],
context: {key: key}, // can't refer to key in success handler, so we sest it as context
success: function(data) {
parsePageCont(data, this.key);
}
}
});
}
}
Well, one problem seems to be that you are assuming that the second dimension of your array is always the same size (ie keyCnt). You also seem to be counting the wrong direction, by which i mean you would get two (inGoodHands and spaRituals), while you are using it for the second index which is 2 for inGoodHands, and 3 for spaRituals)).
It seems like you should be doing something like this:
for(x in serviceCategories) {
for(y in serviceCategories[x]) {
call ajax for serviceCategories[x][y]
}
}
Javascript scope is the function, not the block. While you can put var curcat inside a for loop it's important to understand that you are not creating a different variable for each iteration.
This means that all the closures you are creating in the loop will actually be based on the same variable so what you probably observed is not that only the first works, but that all of them worked by they were all working on the last key.
The solution for creating a local scope in javascript is to use a local function; instead of
(function(data){ parsePageCount(data, curcat); })
you could use
(function(x){return function(data){ parsePageCount(data, x); };})(curcat)
where the name x has been used instead of curcat to make clear the distinction.
This variable will be indeed separate for each of the created closures.

Categories