Javascript indexing array issue - javascript

Hi I have an array that hold the following numbers, however when I loop though the eachNode function(which iterates 13 times) it repeats all the list elements 13 times. I tested everything but it still produces an error, I'm I executing the for loop correctly?
list[61,67,78]
var len = list.length;
fd.graph.eachNode(function (node) { // loops thru all node id's in graph (13)
for (var i = 0; i < len; ++i) {
if (i in list) {
var nody = list[i]; // I put the number in a variable
var nodess = fd.graph.getNode(nody); //this takes the number and matches it with a node id, it "odjectify" it
if (node.id != nodess.id) { // if the list nodes are not the same
node.setData('alpha', 0); //
node.eachAdjacency(function (adj) { // this make the unmatched nodes disappear
adj.setData('alpha', 0, 'end');
});
}
}
}
});

This line is unneeded:
if (i in list)
The in keyword returns true if its right operand contains the property specified by its left operand. When using this with arrays, it returns unexpected results. The behavior of this keyword is insignificant in this context, so you should simply take it out.
Moreover, you need to create the list array like this:
var list = [61, 67, 78];
...however, when I loop though eachNode (which iterates 13 times) it repeats all the list elements 13 times
It doesn't, it in fact iterates over eachNode 13 times. You also made a for loop which will traverse the list array by its length.
Now that you've given me more detail as to what you want, here is the updated code. I hope it works for you:
fd.graph.eachNode(function (node) {
var flag = false;
for (var i = 0; i < len; ++i)
{
var nody = list[i];
var nodess = fd.graph.getNode(nody);
if (node.id == nodess.id) {
flag = true; break;
}
}
if (flag)
{
node.setData('alpha', 0);
node.eachAdjacency(function (adj) {
adj.setData('alpha', 0, 'end');
});
}
});

This is the behavior by design:
You loop over the graph (13 times as you say), then inside each iteration you loop over your array (3 items).
If you only want to loop once over your array, just move it out of the outer loop

Related

Include duplicates in for and if loop of array as count number is too small

I'm new to javascript so any help would be greatly appreciated.
What I'm trying to do is cycle through every element in the array and count the number of times the value of an element matches a given condition (even if the value is duplicated).
function loaddata(xml) {
var count = 0;
var i;
var xmlDoc = xml.responseXML;
var z = xmlDoc.getElementsByTagName("group");
if (value1 <= value2) {
for (i = 0; i < (0 + z.length); i++) {
if (z[i].getElementsByTagName("name")[0].childNodes[0].nodeValue == "John") {
count++;
}
}
}
$('#count1').html(count);
};
The count value outputted is too small. I believe the reason for this that the for loop isn't iterating through all elements in the array. When I remove the second if loop and output the count for just the for loop this value is also too small. I believe that the for loop isn't searching through the duplicate elements of the array (i.e. it is ignoring them so that they aren't then fed into the second if loop). Is it possible to specify that the for loop include duplicates?
Do a console.log(z[i].getElementsByTagName("name")) and open your browser's console, and see if that array has data in it.
Then console.log(z[i].getElementsByTagName("name")[0].childNodes) and make sure you have nodes in it.
Also, do you have many <group></group> tags? Because that's what you are selecting with var z = xmlDoc.getElementsByTagName("group");
I hope that helps,

JavaScript - Looping array less than I should

I'm trying to loop an array which contains a list of elements returned by ClassName, but I can't loop all of them, because of the next situation:
var list = document.getElementsByClassName('class');
for (var i = 0; i < list.length; i++) {
var theClass = list[i].className; //once got list[i].
theClass = theClass.replace('class', '');
list[i].className = theClass; //twice got list[i].
}
If the size of the list is = 4, I just can loop two times, because I'm getting twice each position per loop. Do you know what I can do and why it happens? Thank you.
The data structure returned by getElementsByClassName is Array-like and dynamic based on the DOM. Once you replace the class on the list item in question, you end up losing an item per iteration.
To fix this, you can take a copy of the returned values first before operating on them, or work backwards.
Take a copy:
var list = document.getElementByClassName('class')
var realList = []
Array.prototype.push.apply(realList, list)
for (var i = 0; i < realList.length; i++) {
// do changes as you have already
}
Working backwards:
var list = document.getElementsByClassName('class')
for (i=list.length - 1; i >= 0; i--) {
// do changes to list[i]
}
Another poster briefly mentioned a while loop which also works, but then their answer disappeared (I don't want to take credit for this!):
var list = document.getElementsByClassName('class')
while (list.length != 0) {
// do changes to list[0]
}
If you write out what happens in your initial code, you can see the problem more clearly:
Iteration 1: i=0, list=[a,b,c,d], length = 4, list[i]=a
Iteration 2: i=1, list=[b,c,d], length = 3, list[i]=c
Before Iteration 3: list=[b,d], i=2, length = 2, loop breaks
Now writing out what happens when using the reverse loop:
Iteration 1: i=3, list=[a,b,c,d], length = 4, list[i]=d
Iteration 2: i=2, list=[a,b,c], length = 3, list[i]=c
Iteration 3: i=1, list=[a,b], length = 2, list[i]=b
Iteration 4: i=0, list=[a], length = 1, list[i]=a
All these solutions are variations on this solution of avoiding using i to reference the middle parts of the array-like result value of getElementsByClassName so that the dynamic nature of it is dealt with.

recursive function with an array as input

I am trying to create a function that gets chest exercises from an array called chest.
This function needs to be able to pick several exercises at random, which I have done using a random pointer. To stop duplicate exercises I compare the chest exercise picked (i.e chest[pointer]) and compare it against all the values in the final array.
If the new exercise is not already in the final array, the newly picked exercise is returned and then pushed onto the final array. If it is already in the final array, the function is called recursively. The idea being that the function will run recursively until it finds a new exercise which has not already been chosen:
Get Chest:
function getChest(arr){
var pointer = 0;
//random array pointer
pointer = Math.round(Math.random() * (chest.length - 1));
//check for duplicate
for(var i = 0; i < arr.length - 1; i++){
if(arr[i].name === chest[pointer].name){
return getChest(arr);
} else {
return chest[pointer];
}
}
};
The main function uses this method to select exerises randomly. The final array is called 'day'.:
function chooseExercises(){
for(i = 0; i <= 5; i++){
ex = getChest(day);
day.push(ex);
}
}
The problem I am having is that there are still duplicates when I run it. Any idea as to what is going wrong? (I am using angularJS)
Modify your function to this,
function getChest(arr){
var pointer = 0;
//random array pointer
pointer = Math.round(Math.random() * (chest.length - 1));
//check for duplicate
for(var i = 0; i < arr.length; i++){
if(arr[i].name === chest[pointer].name){
return getChest(arr);
}
}
return chest[pointer];
};
Basically, the loop is breaking before the value is checked with its full length.
EDIT: also your loop is running over arr.length-1 times, which actually should be just arr.length.

Skipping multiple elements in a FOR loop, Javascript

I have some file contents I'd like to pass on to my server using a javascript function. In the file, there are many empty lines, or those which contain useless text. So far I read every line in as a string stored in an array.
How do I then loop through that content skipping multiple lines such as lines 24,25, 36, 42, 125 etc. Can I put these element id's into an array and tell my for loop to run on every element except these?
Thanks
you can't tell your for loop to iterate all, but skip certain elements. it will basically just count in any direction (simplified) until a certain critera has been met.
you can however put an if inside your loop to check for certain conditions, and chose to do nothing, if the condition is met. e.g.:
(pseudo code below, beware of typing errors)
for(var line=0; line < fileContents.length; line++) {
if(isUselessLine(line)) {
continue;
}
// process that line
}
the continue keyword basically tells the for loop to "jump over" the rest of the current iteration and continue with the next value.
The isUselessLine function is something you'll have to implement yourself, in a way, that it returns true, if the line with the given linenumber is useless for you.
You can try this its not much elegent but will suerly do the trick
<html>
<body>
<p>A loop which will skip the step where i = 3,4,6,9.</p>
<p id="demo"></p>
<script>
var text = "";
var num = [3,4,6,9];
var i;
for (i = 0; i < 10; i++) {
var a = num.indexOf(i);
if (a>=0) {
continue;
}
text += "The number is " + i + "<br>";
}
document.getElementById("demo").innerHTML = text;
</script>
</body>
You could use something like this
var i = 0, len = array1.length;
for (; i < len; i++) {
if (i == 24 || i == 25) {
array1.splice(i, 1);
}
}
Or you can have an another array variable which got all the items that need to be removed from array1
Another method:
var lines = fileContents.match(/[^\r\n]+/g).filter(function(str,index,arr){
return !(str=="") && uselessLines.indexOf(index+1)<0;
});
If you have many indices to skip, and this depends on the elements of the array, you could write a function that returns the number of elements to skip over for each index in that array (or returns 1, if no skipping required):
for ( let i = 0;
i < array.length;
i += calcNumberOfIndicesToSkip( array, i )){
// do stuff to the elements that aren't
// automatically skipped
}
function calcNumberOfIndicesToSkip( array, i ){
// logic to determine number of elements to skip
// (this may be irregular)
return numberOfElementsToSkip ;
}
In your case:
// skip the next index (i+1)?
for ( let i=0; i<array.length; i+=skipThisIndex(i+1) ){
// do stuff
}
function skipThisIndex(i){
const indicesToSkip = [ 24, 25, 36, 42, 125 ];
return 1 + indicesToSkip.includes(i);
}
// returns 1 if i is not within indicesToSkip
// (there will be no skipping)
// => (equivalent to i++; normal iteration)
// or returns 1 + true (ie: 2) if i is in indicesToSkip
// => (index will be skipped)

How to compare Array value to result of 'for' loop in javascript

I have an empty array (called zoomthumbsarray) which gets values pushed to it whilst a 'for' loop is running. This 'for' loop is checking if a thumbnail image is present in the backend against the particular product the user is viewing. If there is an image it gets added into a vertical slider. The current issue is there are non colour specific images (like lifestyle shots) that are being added into the slider multiple times.
So I need to check if the image found in the for loop is currently stored in the array. If it is present, the image has already been generated and I don't want it to get pulled into the slider again. If it hasn't then the image will get added.
Below is the code I am working on. I would presume indexOf would be used but can't get this to work.
Any help would be really appreciated.
var zoomthumbsarray = [] // Empty array which gets populated by .push below during loop
for (var i = 0; i < storeImgsArr.length; i++) { // storeImgsArr finds the quantity of attributes present against the product. This loops and increments counter if there is another attibute image
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) { // Loop and increment counter if there is a Large image
zoomthumbsarray.push(storeImgsArr[i].images.imgS[e].slice(-16)); // Slices off last 16 characters of image path i.e. _navy_xsmall.jpg or 46983_xsalt1.jpg and pushes this into 'zoomthumbsarray' array
// if statement sits here to build the html to add the image to the slider
}
}
zoomthumbsarray = [] // Resets array to zero
ANSWER
As answered by Chris I used $.unique to only keep unique values in the array.
Then wrap an if statement around the code to build the thumb image html if the array === 0 or if the current image isn't already in the array.
Updated code below:
var zoomthumbsarray = [] // Empty array which gets populated by .push below during loop
for (var i = 0; i < storeImgsArr.length; i++) { // storeImgsArr finds the quantity of attributes present against the product. This loops and increments counter if there is another attibute image
if (zoomthumbsarray === 0 || zoomthumbsarray.indexOf(storeImgsArr[i].images.imgS[e].slice(-16)) < 0) { // If statement is true if array === 0 or if the current image isn't already in the array
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) { // Loop and increment counter if there is a Large image
zoomthumbsarray.push(storeImgsArr[i].images.imgS[e].slice(-16)); // Slices off last 16 characters of image path i.e. _navy_xsmall.jpg or 46983_xsalt1.jpg and pushes this into 'zoomthumbsarray' array
zoomthumbsarray = $.unique(zoomthumbsarray); //Keeps only unique elements
// if statement sits here to build the html to add the image to the slider
}
}
}
zoomthumbsarray = [] // Resets array to zero
Some cheap and dirty ideas:
Using underscore/lodash:
zoomthumbsarray = _.uniq(zoomthumbsarray); //Keeps only unique elements
jQuery has one as well:
zoomthumbsarray = $.unique(zoomthumbsarray); //Keeps only unique elements
then you loop through the array and build HTML.
Update:
There's something a bit odd about the rest of the JS. Might this work (if you're using a new enough browser)?
var zoomthumbsarray = [];
storeImgsArr
.map(function(item) { return item.images.imgS; })
.forEach(function(imgS) {
zoomthumbsarray = zoomthumbsarray.concat(imgS.map(function(imagePath) {
return imagePath.slice(-16);
}));
});
zoomthumbsarray = $.unique(zoomthumbsarray);
I have tried indexOf (see first if statement below) but this doesn't work.
As #elclanrs said, indexOf does return the index in the array not a boolean. You only will need to see if it's >= 0 to test whether an image is already contained in the array.
var zoomthumbsarray = [];
for (var i = 0; i < storeImgsArr.length; i++) {
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) {
var image = storeImgsArr[i].images.imgS[e].slice(-16);
if (zoomthumbsarray.indexOf(image) < 0) { // not yet in the array
zoomthumbsarray.push();
// and build the html to add the image to the slider
}
}
}
If you have really lots of images and notice this starts slowing the page down, then there are too many images in your page anyway. No, joke aside; …then check the optimisation by #Ivey.
instead of using an array you can use an object to store the images as keys and a dummy value (possibly true). then you can extract the keys from this object.
var images = {};
for (var i = 0; i < storeImgsArr.length; i++) {
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) {
images[storeImgsArr[i].images.imgS[e].slice(-16))] = true;
}
}
var zoomthumbsarray = [];
for(var k in images) {
zoomthumbsarray.push(k);
// build the html to add the image to the slider
}
EDIT: Added build html comment

Categories

Resources