Using .push stops for loop from executing - javascript

I have a for loop that suddenly stops working when I try to push to an array. The best way to describe what's going on is just to show my code and try an explain what's going on.
for (var i = 0; i < childs.length; i++) {
if (childs[i].length > 0) {
for (var j = 0; j < amountsValue[i].options.custValues.length; j++) {
var label = amountsValue[i].options.custValues[j].label;
var value = amountsValue[i].options.custValues[j].value;
for (var k = childs[i].length - 1; k >= 0; k--) {
if (childs[i][k].attributes[label] != value) {
childBackup.push(childs[i][k]);
childs[i].splice(k, 1);
}
}
}
amountsValue[i].id = childs[i][0].attributes.internalid;
childs.push(childBackup);
}
}
What's happening is I am looping through an array of items which may or may not have custom options available such as different sizes or colours. The loop will check to see if there are any then get the value and label from the array.
After this, we then loop again to try and match up the values with option values stored within a separate model. The plan is to check if the value is the same as the one stored and if not then splice it from the array. The process of elimination should eventually leave only one option left and that will be used to get the internalid.
During this a back up of the spliced objects is kept so that they can be appended to the array again so that the user can change the option they want. The problem is using childs.push(childBackup) stops the browser form reading the options on amountsValue. This works if the code is removed or it is pushed into another index so I'm really not sure why it isn't working.
Does anyone have any suggestions on how to get this working? I'm sorry if this doesn't make much sense, I've tried to explain it as best I can but let me know if anything needs to be cleared up.
EDIT: I have fixed the issue. Thank you to everyone who suggested ways to solve the problem. As others said, I was trying to manipulate the array I was looping through and changing the length on it. So that part of the code was taken outside the loop and after the initial loop another loop was set up which contained the following code:
for (var i = 0; i < childBackup.length; i++) {
childs[0].push(childBackup[i]);
}
It now works as intended. Thank you.

You are manipulating the array you are looping through.
var count = childs.length;
for (var i = 0; i < count; i++) {
if (childs[i].length > 0) {
for (var j = 0; j < amountsValue[i].options.custValues.length; j++) {
var label = amountsValue[i].options.custValues[j].label;
var value = amountsValue[i].options.custValues[j].value;
for (var k = childs[i].length - 1; k >= 0; k--) {
if (childs[i][k].attributes[label] != value) {
childBackup.push(childs[i][k]);
childs[i].splice(k, 1);
}
}
}
amountsValue[i].id = childs[i][0].attributes.internalid;
childs.push(childBackup);
}
}

Related

Array index out of bounds in Angular 2

I want to declare an Array with 4 dimensions, then loop some stuff with for() - and then the program breaks. Here is my code:
Typescript:
MoarInfo: any = [[[[]]]];
JavaScript:
constructor(){
for(var i = 0; i < this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth].length; i++){
for(var a = 0; a < this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i].length; a++){
for(var b = 0; b < this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a].length; b++){
this.MoarInfo[i][a][b][0] = this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a][b][0];
this.MoarInfo[i][a][b][1] = this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a][b][1];
this.MoarInfo[i][a][b][2] = 'DetailsSpan';
}
}
}
}
The Problem definitively lies at the MoarInfo[][][][] array. I tested my code without it, and it works fine. I tried the following possibilities for the Typescript array declaration as well:
Moarinfo: any[]; MoarInfo = []; MoarInfo = [[[[]]]]; MoarInfo: any[][][][] = [[[[]]]];
And in JavaScript, I tried to declare a new Array, and then push some elements on the MoarInfo array, with different functions (split, unshift, push, concat) and nothing worked.
What am I doing wrong?
Check the size of this.MoarInfo[i][a][b]. You are trying to get the value by index 0,1,2. Looks like its size is less than 2 which is causing this error.
if(this.MoarInfo[i][a][b].size > 0){
this.MoarInfo[i][a][b][0] = this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a][b][0];
}
if(this.MoarInfo[i][a][b].size > 1){
this.MoarInfo[i][a][b][1] = this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a][b][1];
}
if(this.MoarInfo[i][a][b].size > 2){
this.MoarInfo[i][a][b][2] = 'DetailsSpan';
}
Okay, I figured it out for myself. You have to set the elements of the dimensions from the array at first blank, then you can fill them with content. First I declared an Array in TypeScript like this AnArray = [];. Then I switched to JavaScript ( to the constructer() function ) and filled it with blank elements. I archieved this with this.AnArray.push();. If you want to set elements for the first dimension use push([]);, if you want an element for the 4th dimension, use push([[[]]]);. And you can set your content space like this push([[['E1',0,0,'E2']]]);. Now you can use follwing syntax:
alert( this.AnArray[0][0][0][3] ); //returns 'E2'
The complete code from my project now works fine and looks like this:
for(var i = 0; i < this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth].length; i++){
this.test.push([[[]]]);
for(var a = 0; a < this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i].length; a++){
this.test[i].push([[]]);
for(var b = 0; b < this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a].length; b++){
this.test[i][a].push(['',0,'']);
this.test[i][a][b][0] = this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a][b][0];
this.test[i][a][b][1] = this.AllDataInfo[this.KontoAktuellYearIndex][this.KontoAktuellMonth][i][a][b][1];
this.test[i][a][b][2] = 'DetailsSpan';
}
}
}
I wonder if there is a better way than using arrays, but if you want it too, you can do it like this.
cheers

Check if the elements in array have been connected into a pair in Javascript

I have a problem that I can't seem to solve, maybe you can help.
There is an array I have. E.g. ['#dog','#cat','#mouse']
I want to reiterate through each value in that array and connect it to all the other values in that same array (through building a DB query).
However, because I'll be writing that in a database I need to avoid duplicates.
So if the #cat has been already connected to #mouse then by the time my for statement reaches the #mouse i want it to skip adding connection to #cat (and also to #dog because it was already connected on the first iteration to #mouse.
I've been trying with for loops, such as
for (var i=0; i<animals.length; i++) {
for (var j = 0; j<animals.length; j++) {
if (animals[i] !== animals[j]) {
// adds connection between animals[i] and animals[j]
}
}
}
But what's the best way to implement a check of the already existing pairs? (where it doesn't matter which element is the first, which is the second - e.g. my graph is not unidirectional).
This especially becomes a problem if I'm going to have more than 4 elements in the array...
Thank you for your help!
for (var i=0; i<animals.length; i++) {
for (var j = 0; j<i; j++) {
if (animals[i] !== animals[j]) {
// adds connection between animals[i] and animals[j]
}
}
}
This way, each element of the array is only compared against those before it in the array. I think this is much closer to what you want.
In the inner loop, you only want to make connections to elements not yet visited by the outer loop:
for (var i=0; i<animals.length; i++) {
for (var j = i+1; j<animals.length; j++) {
// ^^^
// adds connection between animals[i] and animals[j]
}
}
That way you won't get duplicate edges (assuming that animals itself is duplicate-free)

How to match and remove an object from javascript array?

I am trying to delete an element based on string match for a object property but when I do a slice on the javascript array the array size decreases and indexes change. Please help e with a solution. Here is a jsfiddle link for the same.
Code
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
}
}
}
Add i--;
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
selection.splice(i, 1);
i--;
}
}
}
jsfiddle example
Assuming you don't have a problem with having undefined as the new value, then you could call delete[i]; instead of selection.splice(i, 1); in that case the length does not change and neither will the indices.
Both Abhi1964 and Loolooii solution seems to work fine and solve problem, but i would personally keep the filtered results in separate array instead of manipulating index/deleting value in the same array, reason being, separate array would make code look simpler to read and understand. Reviewer need not to understand the index manipulation or keep track of undefined.
var selection = JSON.parse('[{"Connectors":"c1"},{"Connectors":"c2"},{"Schedules":"s1"},{"Schedules":"s2"},{"Gauges":"g1"},{"Gauges":"g2"},{"Gauges":"g3"}]');
removeitem("Gauges");
var filteredResult = [];
function removeitem(item) {
for (var i = 0; i < selection.length; i++) {
if (selection[i].hasOwnProperty(item)) {
}else{
filteredResult.push(item);
}
}
}
//use filtered result as per your need.
Note:
I have not run this code, if some error seems to be there, please feel free to edit.

get string of values of certain property from JSON

I'm trying to get a string of ISBNs from a Google Books bookshelf via their API. Here's my attempt that isn't working. (I'm trying to use this snippet.)
$.getJSON("https://www.googleapis.com/books/v1/users/115939388709512616120/bookshelves/1004/volumes?key=MYAPIKEY", function (data) {
console.log(data);
var allIsbns = [];
for (i = 0; i < data.items.volumeInfo.industryIdentifiers[0].identifier.length; i++) {
allIsbns.push(data.items.volumeInfo.industryIdentifiers[0].identifier[i]);
}
alert(allIsbns);
});
fiddle
Looking at the object logged, data.items is an array (of length data.totalItems it seems). Furthermore, industryIdentifiers[0].identifier seems to be a string, and not an array. Therefore I think you wanted to loop through data.items instead.
Also it may be worth noting you probably should not be going by explicit index on industryIdentifiers unless the the spec calls out a predefined order. I would recommend finding the identifier with type === "ISBN_10":
for (var i = 0; i < data.items.length; i++) {
for (var j = 0; j < data.items[i].volumeInfo.industryIdentifiers.length; j++) {
if (data.items[i].volumeInfo.industryIdentifiers[j].type === "ISBN_10")
allIsbns.push(data.items[i].volumeInfo.industryIdentifiers[j].identifier);
}
}

Why is my nested for loop not working as I expected?

I have trouble dealing with my for loops now, I'm trying to compare two datum, basically it will compare 2 items, then it will write the matches and the mismatches on the webpage.
I managed to write the matches on the webpage, it was working good. But there's a bug in my mismatch compare.
It wrote all the data on the webpage X times, here's my JS code:
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
var count = 0;
var count2 = 0;
for(var i = 0; i < i1.length; i++) {
for(var j = 0; j < i2.length; j++) {
if(i1[i] == i2[j]) {
newArray.push(i1[i]);
count++;
} if (i1[i] !== i2[j]) {
newArray2.push(i1[i]);
count2++;
}
}
}
count-=2;
count2-=2
writeHTML(count,count2, newArray, newArray2);
}
The result was horrible for the mismatches:
alt text http://www.picamatic.com/show/2009/03/01/07/44/2523028_672x48.jpg
I was expecting it to show the mistakes, not all the strings.
The issue you're seeing is because of the nested for loop. You are essentially doing a cross-compare: for every item in i1, you are comparing it to every item in i2 (remember that j starts again at 0 every time i advances... the two loops don't run in parallel).
Since I understand from the comments below that you want to be able to compare one array to the other, even if the items in each are in a different order, I've edited my original suggestion. Note that the snippet below does not normalize differences in case between the two arrays... don't know if that's a concern. Also note that it only compares i1 against i2... not both i1 to i2 and i2 to i1, which would make the task a little more challenging.
function testItems(i1, i2) {
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++) {
var found = false;
for (var j = 0; j < i2.length; j++) {
if (i1[i] == i2[j]) found = true;
}
if (found) {
newArray.push(i1[i])
} else {
newArray2.push(i1[i])
}
}
}
As an alternative, you could consider using a hash table to index i1/i2, but since the example of strings in your comment include spaces and I don't know if you're using any javascript helper libraries, it's probably best to stick with the nested for loops. The snippet also makes no attempt to weed out duplicates.
Another optimization you might consider is that your newArray and newArray2 arrays contain their own length property, so you don't need to pass the count to your HTML writer. When the writer receives the arrays, it can ask each one for the .length property to know how large each one is.
Not directly related to the question but you should see this:
Google techtalks about javascript
Maybe it will enlighten you :)
Couple of things about your question. First you should use '!=' instead of '!==' to check inequality. Second I am not sure why you are doing decreasing counts by 2, suggests to me that there may be duplicates in the array?! In any case your logic was wrong which was corrected by Jarrett later, but that was not a totally correct/complete answer either. Read ahead.
Your task sounds like "Given two set of arrays i1 & i2 to find i1 {intersection} i2 and i1{dash} {UNION} i2{dash}) (Group theory notation). i.e. You want to list common elements in newArray and uncommon elements in newArray2.
You need to do this.
1) Remove duplicates in both the arrays. (For improving the program efficiency later on) (This is not a MUST to get the desired result - you can skip it)
i1 = removeDuplicate(i1);
i2 = removeDuplicate(i2);
(Implementation for removeDuplicate not given).
2) Pass through i1 and find i1{dash} and i1 {intersection} i2.
var newArray = [];
var newArray2 = [];
for (var i = 0; i < i1.length; i++)
{
var found = false;
for (var j = 0; j < i2.length; j++)
{
if (i1[i] == i2[j])
{
found = true;
newArray.push(i1[i]); //add to i1 {intersection} i2.
count++;
break; //once found don't check the remaining items
}
}
if (!found)
{
newArray2.push(i1[i]); //add i1{dash} to i1{dash} {UNION} i2{dash}
count2++;[
}
}
3) Pass through i2 and append i2{dash} to i1{dash}
for(var x=0; x<i2.length; x++)
{
var found = false;
//check in intersection array as it'd be faster than checking through i1
for(var y=0; y<newArray.length; y++) {
if( i2[x] == newArray[y])
{
found = true;
break;
}
}
if(!found)
{
newArray2.push(i2[x]); //append(Union) a2{dash} to a1{dash}
count2++;
}
}
writeHTML(count,count2, newArray, newArray2);
I have a feeling that this has to do with your second comparison using "!==" instead of "!="
"!==" is the inverse of "===", not "==". !== is a more strict comparison which does not do any type casting.
For instance (5 != '5') is false, where as (5 !== '5') is true. This means it's possible that you could be pushing to both arrays in the nested loop, since if(i1[i] == i2[j]) and if(i1[i] !== i2[j]) could both be true at the same time.
The fundamental problem here is that a pair of nested loops is NOT the right approach.
You need to walk a pointer through each dataset. ONE loop that advances both as needed.
Note that figuring out which to advance in case of a mismatch is a much bigger problem than simply walking them through. Finding the first mismatch isn't a problem, getting back on track after finding it is quite difficult.

Categories

Resources