Last active
June 27, 2018 05:21
-
-
Save LearningNerd/b27ace0a2ffdca4d9f1394d2b676ca5e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Loops, and stepping through loops one step at a time, triggered by an external event | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
let testArray = [1,2,3,4,5]; | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// FIRST -- a simple while loop, for comparison: | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
let index = 0; | |
while (index < 5) { | |
let element = testArray[index]; | |
console.log(index + ": " + element); | |
// Don't forget to iterate! A while loop makes this more obvious: | |
index++; | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 2 -- Advance the loop in stages | |
// Need a trigger to advance to next step -- in this case, a click: | |
document.addEventListener("click", stepThroughLoop); | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
///// 2A: Condition inside stepper function | |
// NOTICE: The code below perfectly mirrors a while loop; just replace the "while" line with the "function" line, | |
// and the condition would go inside the function (so it will stop running the code after a certain number of iterations) | |
// (OR: check for the negative condition instead and return to exit the function) | |
let index = 0; | |
function stepThroughLoop () { | |
if (index < 5) { | |
let element = testArray[index]; | |
console.log(index + ": " + element); | |
index++; | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
///// 2B: No condition; instead of simply iterating, wrap back to the start when end is reached | |
///// (modular arithmetic, yay!) | |
// NOTICE: Without a condition, we can cycle through all elements or do infinite looping | |
let index = 0; | |
function stepThroughLoop () { | |
let element = testArray[index]; | |
console.log(index + ": " + element); | |
// When index reaches last element, wrap back to the start; otherwise just increment | |
index = (index === testArray.length - 1 ? 0 : index + 1); | |
// Or keep an incrementer and use remainder operator, as in: | |
// incrementer++; | |
// index = incrementer % testArray.length; | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// STEPPING THROUGH ***NESTED*** LOOPS | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// FIRST -- A nested while loop for comparison: | |
// NOTES: - Only need to initialize the outerIndex outside the loop. | |
// - The innerIndex NEEDS to be defined within the outer loop, before the inner loop. | |
// - They are indeed NESTED, one loop within the other | |
let outerIndex = 0; | |
while (outerIndex < 5) { | |
let innerIndex = 0; | |
while (innerIndex < 3) { | |
console.log(outerIndex + " -- " + innerIndex); | |
innerIndex++; | |
} | |
outerIndex++; | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3A -- ADVANCE THROUGH NESTED LOOP IN STAGES | |
// Notes: - All the incrementers must be initialized outside of the looping function. | |
// - Using a toggle to switch between running the inner or outer loop. | |
// - The inner and outer loops' conditional blocks must NOT be nested, | |
// ...because only ONE of them should increment at a time, never both. | |
// - In this version, the inner loop's conditional block happens FIRST, | |
// ...otherwise when the inner loop is done and switching back to the outer, | |
// ...there will be one iteration that runs NEITHER loop. | |
// *** This isn't the only way to do it, though! (I'm pretty sure) | |
// *** Update: after tinkering some more, I'm starting think this IS the only way. | |
// - The outerIndex increments once BEFORE anything else starts, | |
// ...so it effectively starts at 1 if initialized at 0. | |
// - Both loops run one extra time, so if the condition is index < 5, it'll run 6 times. | |
// *** Why exactly?? Take a closer look at this! | |
document.addEventListener("click", stepThroughNestedLoop); | |
let outerIndex = 0; | |
let innerIndex = 0; | |
let isInnerLoop = false; | |
function stepThroughNestedLoop () { | |
if (innerIndex < 3 && isInnerLoop) { | |
innerIndex++; | |
} else if (innerIndex >= 3) { | |
isInnerLoop = false; | |
innerIndex = 0; | |
} | |
if (outerIndex < 5 && !isInnerLoop ) { | |
isInnerLoop = true; | |
outerIndex++; | |
} | |
console.log(outerIndex + " -- " + innerIndex); | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3B -- CLEANER, FIXED OFF-BY-ONE ISSUES -- ADVANCE THROUGH NESTED LOOP IN STAGES | |
// NOTES - Avoiding the initialization off-by-one issue by console.log-ing FIRST instead of last | |
// - Nested if-statement handles the switch-off from inner to outer loop by resetting | |
// innerIndex and incrementing outerIndex in the same iteration, so no extra iterations! | |
// - Better to return early if none of the other code needs to run (This also prevents extra iterations) | |
document.addEventListener("click", stepThroughNestedLoop); | |
let outerIndex = 0; | |
let innerIndex = 0; | |
let isInnerLoop = true; | |
function stepThroughNestedLoop () { | |
if (outerIndex >= 5) { | |
return; | |
} | |
console.log(outerIndex + " -- " + innerIndex); | |
if (isInnerLoop) { | |
innerIndex++; | |
if (innerIndex >= 3) { | |
isInnerLoop = false; | |
innerIndex = 0; | |
} | |
} | |
if (!isInnerLoop) { | |
outerIndex++; | |
isInnerLoop = true; | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// FIXED -- ADVANCE THROUGH NESTED LOOP IN STAGES | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// FIRST -- An UPDATED nested while loop for comparison: | |
// NOTES: - I forgot to look at the pattern of *both* indexes in *both* the innter and outer loops! | |
// - I didn't realize this pattern is true for normal loops as well: for each iteration of the outer loop, | |
// *both* the outer and inner console.log statements will run, resulting in seeing the same message twice! | |
// - Example: 0,0 / 0,0 / 0,1 / 0,2 / 1,0 / 1,0 / 1,1 / 1,2 / ...etc... | |
let outerIndex = 0; | |
while ( outerIndex < 5 ) { | |
let innerIndex = 0; | |
console.log(outerIndex + " -- " + innerIndex); | |
while ( innerIndex < 3 ) { | |
console.log(outerIndex + " -- " + innerIndex); | |
innerIndex++; | |
} | |
console.log(outerIndex + " -- " + innerIndex); | |
outerIndex++; | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3C -- FIXED -- ADVANCE THROUGH NESTED LOOP IN STAGES | |
// NOTES - Split the outer loop section in half, one before and one after the inner loop section, | |
// so code can run before AND after the inner loop, just like in a normal nested loop. | |
// - Compared to version 2B, here the outer loop does run FIRST, like a normal nested loop | |
// - Example: 0,0 / 0,0 / 0,1 / 0,2 / 1,0 / 1,0 / 1,1 / 1,2 / ...etc... < startOuterLoop and innerLoop | |
document.addEventListener("click", stepThroughNestedLoop); | |
let outerIndex = 0; | |
let innerIndex = 0; | |
let isInnerLoop = false; | |
function stepThroughNestedLoop () { | |
if (outerIndex >= 5) { | |
return; | |
} | |
if (!isInnerLoop) { | |
console.log(outerIndex + " -- " + innerIndex); | |
isInnerLoop = true; | |
} | |
if (isInnerLoop) { | |
console.log(outerIndex + " -- " + innerIndex); | |
innerIndex++; | |
if (innerIndex >= 3) { | |
isInnerLoop = false; | |
innerIndex = 0; | |
} | |
} | |
if (!isInnerLoop) { | |
console.log(outerIndex + " -- " + innerIndex); | |
outerIndex++; | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3D -- GENERALIZED TEMPLATE -- ADVANCE THROUGH NESTED LOOP IN STAGES | |
// NOTES - Same exact code as 3C, but parameterized to take functions as inputs, | |
// separating the looping logic from the code that needs to be looped. | |
// - NOTE: for now, no parameterization for the incrementors | |
// - NOTE: Any variables (except indexes) will need to be global | |
stepThroughNestedLoop (0, 0, triggerF, innerC, outerC, startOuterF, innerF, endOuterF); | |
// Defining the trigger for step-by-step iteration | |
// Note: MUST use a loop parameter to hook into the internal looping function | |
function triggerF (loop) { | |
document.addEventListener("click", loop); | |
} | |
// Defining conditions and code to run for inner and outer loops: | |
// Note: These next four functions MUST use parameters for indexes | |
function innerC (innerIndex, outerIndex) { | |
return innerIndex < 3; | |
} | |
function outerC (innerIndex, outerIndex) { | |
return outerIndex < 5; | |
} | |
function startOuterF (innerIndex, outerIndex) { | |
console.log(outerIndex + " -- " + innerIndex); | |
} | |
function innerF (innerIndex, outerIndex) { | |
console.log(outerIndex + " -- " + innerIndex); | |
} | |
function endOuterF (innerIndex, outerIndex) { | |
console.log(outerIndex + " -- " + innerIndex); | |
} | |
function stepThroughNestedLoop (initInnerIndex, initOuterIndex, triggerF, innerC, outerC, startOuterF, innerF, endOuterF) { | |
let innerIndex = initInnerIndex; | |
let outerIndex = initOuterIndex; | |
let isInnerLoop = false; | |
triggerF(loop); | |
function loop() { | |
if ( !outerC(innerIndex, outerIndex) ) { | |
return; | |
} | |
if (!isInnerLoop) { | |
startOuterF(innerIndex, outerIndex); | |
isInnerLoop = true; | |
} | |
if (isInnerLoop) { | |
innerF(innerIndex, outerIndex); | |
innerIndex++; | |
if ( !innerC(innerIndex, outerIndex) ) { | |
isInnerLoop = false; | |
innerIndex = initInnerIndex; | |
} | |
} | |
if (!isInnerLoop) { | |
endOuterF(innerIndex, outerIndex); | |
outerIndex++; | |
} | |
} //end loop() | |
} //end stepThroughNestedLoop() | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3E -- FIXING IT UP SOME MORE (see next sections below) | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// FIRST -- A nested while loop for comparison: | |
// NOTES: - Added more console.logs to be more thorough in my comparisons | |
// - Notice: in the last half of the outer loop, the innerIndex has a value of 3 here! | |
let outerIndex = 0; | |
while ( outerIndex < 5 ) { | |
let innerIndex = 0; | |
console.log("==============================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("==============================="); | |
while ( innerIndex < 3 ) { | |
console.log("--------------------"); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("--------------------"); | |
innerIndex++; | |
} | |
console.log("=================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("=================="); | |
outerIndex++; | |
} | |
/* OUTPUT: | |
=============================== | |
0 -- 0 | |
=============================== | |
-------------------- | |
0 -- 0 | |
-------------------- | |
0 -- 1 | |
-------------------- | |
0 -- 2 | |
================== | |
0 -- 3 | |
================== | |
=============================== | |
1 -- 0 | |
=============================== | |
-------------------- | |
1 -- 0 | |
-------------------- | |
1 -- 1 | |
-------------------- | |
1 -- 2 | |
================== | |
1 -- 3 | |
================== | |
=============================== | |
2 -- 0 | |
=============================== | |
-------------------- | |
2 -- 0 | |
-------------------- | |
2 -- 1 | |
-------------------- | |
2 -- 2 | |
================== | |
2 -- 3 | |
================== | |
=============================== | |
3 -- 0 | |
=============================== | |
-------------------- | |
3 -- 0 | |
-------------------- | |
3 -- 1 | |
-------------------- | |
3 -- 2 | |
================== | |
3 -- 3 | |
================== | |
=============================== | |
4 -- 0 | |
=============================== | |
-------------------- | |
4 -- 0 | |
-------------------- | |
4 -- 1 | |
-------------------- | |
4 -- 2 | |
================== | |
4 -- 3 | |
================== | |
*/ | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3E -- FIXED ONE MORE BUG -- HARD-CODED EXAMPLE OF NEW STEP-THROUGH LOOP | |
// NOTES: - Easy fix: Now resetting the innerIndex to its initial value at the start of the outer loop, | |
// just like how it works in the while loop example! (This whole time I've been over-thinking | |
// this. I should've just copied *every detail* from the while loop example from the get-go! | |
document.addEventListener("click", stepThroughNestedLoop); | |
let outerIndex = 0; | |
let innerIndex = 0; | |
let isInnerLoop = false; | |
function stepThroughNestedLoop () { | |
if (outerIndex >= 5) { | |
return; | |
} | |
if (!isInnerLoop) { | |
innerIndex = 0; | |
console.log("==============================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("==============================="); | |
isInnerLoop = true; | |
} | |
if (isInnerLoop) { | |
console.log("--------------------"); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("--------------------"); | |
innerIndex++; | |
if (innerIndex >= 3) { | |
isInnerLoop = false; | |
} | |
} | |
if (!isInnerLoop) { | |
console.log("=================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("=================="); | |
outerIndex++; | |
} | |
} | |
/* OUTPUT: | |
=============================== | |
0 -- 0 | |
=============================== | |
-------------------- | |
0 -- 0 | |
-------------------- | |
-------------------- | |
0 -- 1 | |
-------------------- | |
-------------------- | |
0 -- 2 | |
-------------------- | |
================== | |
0 -- 3 | |
================== | |
=============================== | |
1 -- 0 | |
=============================== | |
-------------------- | |
1 -- 0 | |
-------------------- | |
-------------------- | |
1 -- 1 | |
-------------------- | |
-------------------- | |
1 -- 2 | |
-------------------- | |
================== | |
1 -- 3 | |
================== | |
=============================== | |
2 -- 0 | |
=============================== | |
-------------------- | |
2 -- 0 | |
-------------------- | |
-------------------- | |
2 -- 1 | |
-------------------- | |
-------------------- | |
2 -- 2 | |
-------------------- | |
================== | |
2 -- 3 | |
================== | |
=============================== | |
3 -- 0 | |
=============================== | |
-------------------- | |
3 -- 0 | |
-------------------- | |
-------------------- | |
3 -- 1 | |
-------------------- | |
-------------------- | |
3 -- 2 | |
-------------------- | |
================== | |
3 -- 3 | |
================== | |
=============================== | |
4 -- 0 | |
=============================== | |
-------------------- | |
4 -- 0 | |
-------------------- | |
-------------------- | |
4 -- 1 | |
-------------------- | |
-------------------- | |
4 -- 2 | |
-------------------- | |
================== | |
4 -- 3 | |
================== | |
*/ | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 3E -- FIXED ONE MORE BUG -- GENERALIZED STEP-THROUGH LOOP | |
// NOTES: - Same as above, but the generalized template function. | |
stepThroughNestedLoop (0, 0, triggerF, innerC, outerC, startOuterF, innerF, endOuterF); | |
// Defining the trigger for step-by-step iteration | |
// Note: MUST use a loop parameter to hook into the internal looping function | |
function triggerF (loop) { | |
document.addEventListener("click", loop); | |
} | |
// Defining conditions and code to run for inner and outer loops: | |
// Note: These next four functions MUST use parameters for indexes | |
function innerC (innerIndex, outerIndex) { | |
return innerIndex < 3; | |
} | |
function outerC (innerIndex, outerIndex) { | |
return outerIndex < 5; | |
} | |
function startOuterF (innerIndex, outerIndex) { | |
console.log("==============================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("==============================="); | |
} | |
function innerF (innerIndex, outerIndex) { | |
console.log("--------------------"); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("--------------------"); | |
} | |
function endOuterF (innerIndex, outerIndex) { | |
console.log("=================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("=================="); | |
} | |
function stepThroughNestedLoop (initInnerIndex, initOuterIndex, triggerF, innerC, outerC, startOuterF, innerF, endOuterF) { | |
let innerIndex = initInnerIndex; | |
let outerIndex = initOuterIndex; | |
let isInnerLoop = false; | |
triggerF(loop); | |
function loop() { | |
if ( !outerC(innerIndex, outerIndex) ) { | |
return; | |
} | |
if (!isInnerLoop) { | |
innerIndex = initInnerIndex; | |
startOuterF(innerIndex, outerIndex); | |
isInnerLoop = true; | |
} | |
if (isInnerLoop) { | |
innerF(innerIndex, outerIndex); | |
innerIndex++; | |
if ( !innerC(innerIndex, outerIndex) ) { | |
isInnerLoop = false; | |
} | |
} | |
if (!isInnerLoop) { | |
endOuterF(innerIndex, outerIndex); | |
outerIndex++; | |
} | |
} //end loop() | |
} //end stepThroughNestedLoop() | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 4A -- ONLY RUN ONE STEP AT A TIME -- HARD-CODED EXAMPLE OF NEW STEP-THROUGH LOOP | |
// NOTES: - All I had to do was add a return statement to the end of the first half of the outer loop! | |
// - The inner loop and last half of the outer loop do run in the same step, though. I think that's OK. | |
// - Also made the inner loop condition more specific, to avoid the case where if the last half of the | |
// outer loop changes the values for the inner loop's condition, the inner loop will run when it shouldn't. | |
document.addEventListener("click", stepThroughNestedLoop); | |
let outerIndex = 0; | |
let innerIndex = 0; | |
let isInnerLoop = false; | |
function stepThroughNestedLoop () { | |
if (outerIndex >= 5) { | |
return; | |
} | |
if (!isInnerLoop) { | |
innerIndex = 0; | |
console.log("==============================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("==============================="); | |
isInnerLoop = true; | |
return; | |
} | |
if ( isInnerLoop && innerIndex < 3 ) { | |
console.log("--------------------"); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("--------------------"); | |
innerIndex++; | |
if (innerIndex >= 3) { | |
isInnerLoop = false; | |
} | |
} | |
if (!isInnerLoop) { | |
console.log("=================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("=================="); | |
outerIndex++; | |
} | |
} | |
//////////////////////////////////////////////////////////////////////////////////////////////////// | |
// VERSION 4A -- ONLY RUN ONE STEP AT A TIME -- GENERALIZED STEP-THROUGH LOOP | |
// NOTES: - Same as above, but the generalized template function. | |
stepThroughNestedLoop (0, 0, triggerF, innerC, outerC, startOuterF, innerF, endOuterF); | |
// Defining the trigger for step-by-step iteration | |
// Note: MUST use a loop parameter to hook into the internal looping function | |
function triggerF (loop) { | |
document.addEventListener("click", loop); | |
} | |
// Defining conditions and code to run for inner and outer loops: | |
// Note: These next four functions MUST use parameters for indexes | |
function innerC (innerIndex, outerIndex) { | |
return innerIndex < 3; | |
} | |
function outerC (innerIndex, outerIndex) { | |
return outerIndex < 5; | |
} | |
function startOuterF (innerIndex, outerIndex) { | |
console.log("==============================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("==============================="); | |
} | |
function innerF (innerIndex, outerIndex) { | |
console.log("--------------------"); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("--------------------"); | |
} | |
function endOuterF (innerIndex, outerIndex) { | |
console.log("=================="); | |
console.log(outerIndex + " -- " + innerIndex); | |
console.log("=================="); | |
} | |
function stepThroughNestedLoop (initInnerIndex, initOuterIndex, triggerF, innerC, outerC, startOuterF, innerF, endOuterF) { | |
let innerIndex = initInnerIndex; | |
let outerIndex = initOuterIndex; | |
let isInnerLoop = false; | |
triggerF(loop); | |
function loop() { | |
if ( !outerC(innerIndex, outerIndex) ) { | |
return; | |
} | |
if (!isInnerLoop) { | |
innerIndex = initInnerIndex; | |
startOuterF(innerIndex, outerIndex); | |
isInnerLoop = true; | |
return; | |
} | |
if ( isInnerLoop && innerC(innerIndex, outerIndex) ) { | |
innerF(innerIndex, outerIndex); | |
innerIndex++; | |
if ( !innerC(innerIndex, outerIndex) ) { | |
isInnerLoop = false; | |
} | |
} | |
if (!isInnerLoop) { | |
endOuterF(innerIndex, outerIndex); | |
outerIndex++; | |
} | |
} //end loop() | |
} //end stepThroughNestedLoop() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment