I have an array items. I need to make sure that in the current iteration of the loop I can safely call the next item of the array
for(var i = 0; i < items.length; ++i) {
// do some stuff with current index e.g....
item = items[i];
// then do something with item # i+1
if(items[i+1]) {
//do stuff
}
}
Is this how it is done or if not how/what would be the better way?
P.S. I do not want to do a bound check
If you want to loop through every element except the last one (which doesn't have an element after it), you should do as suggested:
for(var i = 0; i < items.length-1; ++i) {
// items[i+1] will always exist inside this loop
}
If, however, you want to loop through every element -even the last one-, and just add a condition if there is an element after, just move that same condition inside your loop:
for(var i = 0; i < items.length; ++i) {
// do stuff on every element
if(i < items.length-1){
// items[i+1] will always exist inside this condition
}
}
if(items[i+1]) will return false (and not execute the condition) if the next element contains a falsey value like false, 0, "" (an empty String returns false).
Put a value check on variable i and make sure it is less than items.length-1 in order to safely access items[i+1].
for(var i = 0; i < items.length-1; ++i) {
if(items[i+1]) {
//do stuff
}
}
Drop the for loop and use array#forEach, and simply check whether a next value exists:
items.forEach(function (item, index) {
if (!items[index + 1]) return;
// do something with item and items[index + 1]
});
Related
My code starts on first item in the first array and iterate through the second array. If the first item in the first array is the same as the item in the second array the value is printed to the console. So in this snippet Nandos and KFC should print to console.
Then once the first item in the first array has been compared to all of the items in the second array we would move to the second item in the first array and compare it to all the items in the second array.
I want to execute the for loop once the button is clicked.
I tried to make the for loop a function and to execute the function once the button was clicked but nothing happened.
<button id="search">Search</button>
var restaurantsOne = ["Nandos", "King Rooster", "Chick-Fil-A", "Dominos", "KFC"];
var restaurantsTwo = ["Nandos","MacDonalds","Burger King","KFC","Pizza Hut"];
for (var i=0; i<=restaurantsOne.length; i++) {
for (var j=0; j<=restaurantsTwo.length; j++){
if (restaurantsOne[i] == restaurantsTwo[j]){
console.log(restaurantsOne[i]);
}
}
}
I would like the for loop to execute once the button was clicked
You haven't linked the button to the loop! Wrap the loop in a function and then add an 'onclick' handler to the button that references the loop function.
var restaurantsOne = ["Nandos", "King Rooster", "Chick-Fil-A", "Dominos", "KFC"];
var restaurantsTwo = ["Nandos","MacDonalds","Burger King","KFC","Pizza Hut"];
function compareArrays () {
for (var i = 0; i < restaurantsOne.length; i++) {
for (var j = 0; j < restaurantsTwo.length; j++){
if (restaurantsOne[i] == restaurantsTwo[j]){
console.log(restaurantsOne[i]);
}
}
}
}
<button id="search" onclick="compareArrays()">Search</button>
Also, it's worth mentioning that you should use i < restaurantsOne.length instead of i <= restaurantsOne.length because the array index starts from 0 and array[array.length] will actually refer to an index that doesn't exist.
ie.
restaurantsOne.length // 5
restaurantsOne[0] // Nandos
restaurantsOne[1] // King Rooster
restaurantsOne[2] // Chick-
restaurantsOne[3] // Dominoes
restaurantsOne[4] // KFC
restaurantsOne[5] // undefined
I wonder if someone can clarify something for me. I have a bit of code to check an array for overlapping values depending on different values. Basically its the contents of a google sheet in rows and comumns for this is specifically GAS. What I have at the moment is
var e = [[2,4,3,4,2],[1,5,3,6,2],[2,4,3,4,1],[1,4,3,6,1],[2,4,3,6,5]];
var i; //id of entry to check
var j; //id of element to check
var k; //id of entry to compare
for (i in e){ //2D ARRAY ARRAY
for (k in e){ //ELEMENT TO COMPARE
if (e[i][2] === e[k][2] && e[i][3] === e[k][3] && e[i][0] && e[i][0] >= e[k][0] && e[i][1] <= e[k][1] && e[i][4] <= e[k][4] && i !=k){
e.splice(i,1);
continue;
}
}
}
return e;
I had to add the continue; as otherwise if the last array checked was also marked for splice the code failed. But I assumed break would also work in place of continue but for some reason it does not. I thought break would return to the outside loop but does it permanently break that bit of code?
Thanks people
EDIT: spoke too soon. code still fails even with continue. head scratching continues
continue jumps directly to the next iteration, so:
while(true) {
console.log("a");
continue;
console.log("b");
}
will only log a as it will jump back to the beginnig of the loop if it reaches continue.If you however move continue to the last line of the loop (just as in your code) it does nothing as it would jump to the begining to the loop one line later, so it just skips an empty line.
I thought break would return to the outside loop
Yup, thats what happens and that is actually a good thing as if you removed the element already, it won't make sense to check for other dupes as you don't want to remove it twice.
Now the real problem is that splice changes the indexes, so if you splice out the fourth element, the fith element becomes the fourth element, but the loop continues to the fith element without checking the fourth element again (which is now a different one). Therefore you have to go back by one element before you break:
for(let i = 0; i < e.length; i++) {
for(let k = 0; k < e.length; k++) {
if(i === k) continue; // < good usecase
if(/* equality checks */) {
e.splice(i, 1); // remove the element
i--; // go back by one as we changed the order
break; // exit the inner loop
}
}
}
IMO:
1) I would favor for(const [i, value] of arr.entries() over for..in
2) you will forget what arr[i][2] is very soon, giving proper names to the indexes makes it way more readable:
const [idA, someValueA] = e[i];
const [idB, someValueB] = e[k];
if(idA === idB && someValueA <= someValueB // ...
3) e is a bad name.
You can use a labelled break to break out of nested loops.
eg
var num = 0;
outermost:
for(var i = 0; i < 10; i++){
for(var j = 0; j < 10 ; j++){
if(i == 5 && j == 5){
break outermost;
}
num++;
}
}
I have an array rosters and i want to alter this array according to some conditions. Here what I'm trying to do.
somefunction(callback) {
for (var i in this.rosters) {
var roster = this.rosters[i];
if (roster.age > 7200) {
this.rosters.splice(i, 1);
} else {
this.rosters[i].age = this.EMarshal.tu.getAgeOfTime(
this.EMarshal.tu.getMyTime(
this.EMarshal.tu.getMyDate(roster.date), roster.shifttime
)
);
console.log(this.rosters[i].age);
}
}
callback();
}
When the the if condition is true and splice is been called, control comes out of from loop and call callback(). But i want to run the loop for each values in the array.
plz carefully notice that there are rosters and roster 2 different variables.
Any idea why its happening and the solution will be usefull.
Thanks
It's just because you are trying to alter the array on which you are iterating.
So, just ad some logic to store the indexes as you have said you have tried.
Here is one suggestion
before getting into loop var index = [];
then your if condition
if (roster.age > 7200) {
index.push(i);
}
and then after the loop, remove those indexes from rosters
for (var j = index.length - 1; j > -1; j-- ) {
console.log(j);
this.rosters.splice(index[j], 1);
}
Remember to iterate the index from last index otherwise you will remove the 1st index and the trying to remove the last index from the rosters, but now you have removed the element from the array so the length is been changed.
if(document.readyState === 'complete') {
function $(elements) {
var matches = document.querySelectorAll(elements);
for (var i = 0; i < matches.length; i++) {
var item = matches[i];
}
return item;
}
}
$('div.test').style.fontSize = '36px';
<div class="test">asdf</div>
<div class="asdfd">test</div>
<div class="test">test</div>
I'd like to select all elements using querySelectorAll, but this seems to only affect the last element.
You are assigning the variable within the loop which will only return the last one. You should build an array of matches by declaring the variable outside of the loop or return the matches:
function $(elements) {
return document.querySelectorAll(elements);
}
Or:
function $(elements) {
var matches = document.querySelectorAll(elements);
var items = [];
for (var i = 0; i < matches.length; i++) {
items.push(matches[i]);
}
return items;
}
You assign each item to var item in turn.
After you've assigned the last one, you return the current value of item (which is the last one).
Return matches and then loop over it to set the font size of each item in turn.
Let's take a look at what your $ function is doing.
Select all items which match the query
Assign the first item in the list to item...
Assign the nth item to item
Return item which now contains the last element
So $() returns only the last element, and on that object, you are doing the assignment .style.fontSize = '36px'
There is no simple way to implement $ to do exactly what you are trying to. You could try a function which is called like this:
$(selector, {
fontSize : "36px"
});
It would look something like this:
function $(selector, properties) {
var matches = document.querySelectorAll(selector);
for (var i = 0; i < matches.length; i++) {
for (var j in properties) {
matches[i].style[j] = properties[j];
}
}
}
I'd recommend you fully understand what this is doing before moving on.
Also, the way you have used document.readyState makes it redundant. You should enclose the function call in your document.readyState, not the definition.
The variable item not is a array, then it is being overrided on each iteration loop.
Or define a array in order by save all selectors, or add the return in for loop.
Of course! the variable item holds the current iteration match. After the for cycle completes, it will naturally hold the last matched element. Javascript is executed sequentially, meaning the return statement will be executed after the forcycle.
I see you are trying to use chaining. This won't work with your current structure as your selector function will only ever return the last matched element from your querySlectorAll.
I think in this case it would be better to either pass a function that you want to do to each element or return an array/nodelist for another function to use;
function $(elements, method) {
var matches = document.querySelectorAll(elements);
for (var i = 0; i < matches.length; i++) {
method(matches[i]);
}
}
$('div.test', function (elem) {elem.style.fontSize = '36px';});
if(document.readyState === 'complete') {
function $(elements) {
var matches = document.querySelectorAll(elements);
for (var i = 0; i < matches.length; i++) {
var item = matches[i];
}
return item;
}
}
$('div.test').style.fontSize = '36px';
<div class="test">asdf</div>
<div class="asdfd">test</div>
<div class="test">test</div>
I have this loop right here:
function sendBackOne() {
var selected = paper.project.selectedItems;
for (var i = 0; i < selected.length; i++) {
console.log(selected[i].name);
}
where selected is an array with items that i iterate over.
One of the items has a ''name'' property set to ''something''. I don't want to go over that element in my loop,i need to disregard it.
How would i go about doing that?
The best way i can figure is writing an IF/ELSE statement in the loop to check the name and if it's not ''something'' i do what i need to do.
Is this the best way?
Simple:
if (selected[i].name == "something")
continue;
Use continue to head to the next iteration.
Yes it is. You can also use a continue statement like this
var selected = paper.project.selectedItems;
for (var i = 0; i < selected.length; i++) {
if (selected[i].name === "something") continue;
... // Whatever you wanted to do, goes here
}