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.
Related
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);
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 have a string that has data separated by a pipe character (|).
Example
var somestring = "data1|data2|data3";
var separated = somestring.split("|");
I know how to use the split() to separate each data.
However, I don't know how many pipes there will be in the resulting Array.
In jQuery or JavaScript, how do I loop over the array returned?
In jQuery or JavaScript, how do I loop through each separated variable?
You basically just need to iterate over the resulting Array.
jQuery
$.each loop
This method is easy to work with, and benefits in the variables used being encapsulated.
$.each(separated, function(index, chunk) {
// `chunk` is each member of the array.
});
jsFiddle.
Of course, jQuery is JavaScript so any of the below methods will also work.
JavaScript
for loop
This is the recommended way.
for (var i = 0, length = separated.length; i < length; i++) {
var chunk = separated[i];
// `chunk` is each member of the array.
}
jsFiddle.
You'll notice too the length property is cached so it is not looked up on each iteration. Some browsers already optimise for this, however IE appears to still benefit from it cached. It only takes 5 seconds to do, so you may as well keep IE users happy too.
You may want to define i and chunk outside of the for loop, because JavaScript has no block scope (unless you're using let), and those variables will exist before (declaration hoisted) and after (no block scope).
for ( in ) loop
This loop is generally not recommended, as it should be used for iterating over object properties only, not array like member properties.
for (var chunk in separated) {
if ( ! separated.hasOwnProperty(chunk)) {
continue;
}
// `separated[chunk]` is each member of the array.
}
jsFiddle.
This loop will loop over all properties up the prototype chain, so hasOwnProperty() must be used. For this reason it is not recommended for arrays.
for ( of ) loop
This loop is standardized in ECMA 6 and is able to loop over NodeLists and iterators.
for (var chunk of separated) {
// `chunk` is each member of the array.
}
jsFiddle
forEach() method
This method is an addition to the ECMA-262 standard. It's not available in IE8, but it can be shimmed relatively easily.
separated.forEach(function(chunk, index) {
// `chunk` is each member of the array.
});
jsFiddle.
Other specialised methods
If you're looking to iterate for a specific goal, it may be useful to use a specialised iterator. Keep in mind these also don't have the best browser support.
filter method
Creates a mew array of the elements which the associated callback returned truthy for.
separated.filter(function(element) {
return +element > 255;
});
reduce method
Creates a new value based on reducing the elements of the array, from left to right.
separated.reduce(function(accumulator, element) {
return accumulator.concat(element);
}, "");
See also the reduceRight method.
map method
Creates a new array, replacing each element with the returned value of the associated callback.
separated.map(function(element) {
return element.substr(0, 1);
});
every method
Returns a boolean value of which is the result of every element in the array passing the test. This method short circuits, i.e. it returns whenever one element's callback doesn't return truthy.
separated.every(function(element) {
return element.substr(0, 1) == "a";
});
some method
Returns a boolean value of which is the result of some element in the array passing the test. This method short circuits, i.e. it returns whenever one element's callback passes the test.
separated.some(function(element) {
return element.substr(0, 1) == "a";
});
separated.length should be all you need.
str.split() returns an array of values, so in your example, since 'separated' is an array, you could:
for (var i=0, len=separated.length; i < len; i++) {
// do something with separated[i]
}
you can do it in jquery like this
$.each(separated,function(key,item){ alert('here is ' + item + ' at position ' + key) })
If your question really is "how do I loop through each separated variable?" then:
for (var i = 0; i < separated.length; i++)
{
//Do something with separated[i];
}
//or (apparently this is deprecated)
for(var a in separated)
{
//Do something with a
}
Loop through with a FOR...NEXT construct like in most other languages:
var somestring = "data1|data2|data3";
var separated = somestring.split("|");
for (i=0 ; i<separated.length; i++) {
document.write(separated[i]);
document.write("<br/>");
}
I just tried the for...in statement in Javascript.
This gives no error:
var images = document.getElementsByTagName('img');
for(x in images){
document.write(images[x]) + " ");
}
However, this does what it should but gives an error in the FF error console.
for(x in images){
images[x].style.visibility="visible";
}
This made me VERY curious as to what's going on.
Doing this:
for(x in images){
document.write(x);
}
...gave me this:
01234567891011121314151617lengthitemnamedItem
What's there at the end? I assume this makes the document.images / document.getElementsByTagName('img') array not suitable to use with the for...in statement since the values for x at the end won't correspond to an image? Maybe a for loop is better?
Don't iterate through arrays with for ... in loops. Use an index:
for (var i = 0; i < arr.length; ++i) {
// images[i] ...
}
The for ... in construct isn't wrong, it's just not what you want to do; it's for when you want to iterate through all properties of an object. Arrays are objects, and there are other properties besides the semantically-interesting indexed elements.
(Actually what comes back from getElementsByTagName isn't really an Array; it's a node list. You can however treat it like an array and it'll generally work OK. The same basic caveat applies for for ... in in any case.)
for..in does not loop through the indexes of an array, it loops through the enumerable property names of an object. It happens that the only enumerable properties array instances have, by default, are array indexes, and so it mostly works to think it does array indexes in limited situations. But that's not what for..in does, and misunderstanding this will bite you. :-) It breaks as soon as you add any further properties to the array (a perfectly valid thing to do) or any library you're using decides to extend the array prototype (also a valid thing to do).
In any case, what you get back from document.getElementsByTagName isn't an array. It's a NodeList. Your best bet for iterating through NodeLists is to use an explicit index a'la Pointy's answer -- e.g., a straight counting loop:
var i;
for (i = 0; i < list.length; ++i) {
// ... do your thing ...
}
Somewhat off-topic because it doesn't relate to your NodeList, but: When you are actually working with a real array, because arrays in JavaScript are sparse, there is applicability for for..in, you just have to be clear about what you're doing (looping through property names, not indexes). You might want to loop only as many times as the array has actual entries, rather than looping through all the indexes in the gaps in the sparse array. Here's how you do that:
var a, name;
a = [];
a[0] = "zero";
a[10000] = "ten thousand";
for (name in a) {
// Only process this property name if it's a property of the
// instance itself (not its prototype), and if the name survives
// transition to and from a string unchanged -- e.g., it's numeric
if (a.hasOwnProperty(name) && parseInt(name) == name) {
alert(a[name]);
}
}
The above only alerts twice, "zero" and "ten thousand"; whereas a straight counting loop without the checks would alert 10,001 times (mostly saying "undefined" because it's looping through the gap).
The problem with the for ... in construct is that everything from the prototype(s) gets included in the enumeration.
What your output is showing is basically every attribute of images, which is an array object. So you get
all the elements in your array, i.e. the numbers that appear in your output.
all the properties available on your array. This is why you see length in your output for example.
Your code breaks due to number 2, since a functions does not have a style attribute
So, yes, as Pointy shows, the correct way to iterate over the elements of an array in JavaScript is by using a for loop.
phew! That was a long title.
I'm reading WROX' book on Professional JavaScript for web developers and I came across this sample code, and I was just wondering if that was best practice:
function convertToArray(nodes) {
array = new Array();
for (var i=0, len=nodes.length; i < len; i++) {
array.push(nodes[i]);
}
return array;
}
The thing that's got me scratching my head is the "len=nodes.length". Am I wrong in thinking that the first sentence in a for-loop is only run once? Is there a reason you'd want to set a variable (len) to the length of the nodeList before running through it? Would you do that to a normal array as well?
Thanks
That is for performance reasons. A local variable is faster for several reasons:
The the length will need to be accessed all the time in the loop, once per every iteration;
A local variable lookup is faster than member lookup;
If nodes is an array, then .length is a magic property that may take a bit longer to retrieve than a member variable.
If nodes is an ActiveX object, then .length might result in a method call into the object, so that's the most expensive operation of all.
While we're discussing micro-optimizations, the following should be even faster:
function convertToArray(nodes) {
var i = nodes.length,
array = new Array(i); // potentially faster than `array = []`
// -- see comments
while(i--)
array[i] = nodes[i];
return array;
}
It needs one less local variable, uses a while and not a for loop and uses array assignment instead of the function call push().
Also, because we're counting down we pre-allocate the array's slots, the array's length doesn't have to be changed each iteration step, but only on the first one.