ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
The power of nested loops
http://www.actionscript.org/resources/articles/5/1/The-power-of-nested-loops/Page1.html
Neil Webb
Neil Webb is a Flash Platform Developer currently living and working in England. He joined the site when it was just a baby - look at it now! Neil has previously worked for Cambridge University, FIFA and Hutchinson Whampoa among others.
 
By Neil Webb
Published on September 9, 2005
 
Tutorial details:
Written by: Neil Webb (aka Mortimer Jazz) [email:neilwebb@bigfoot.com] | www.nwebb.co.uk
Time: 40 Minutes
Difficulty Level: Intermediate
Requirements: Flash 5, Flash MX
Topics Covered: Nested Loops
Assumed knowledge: For-loops, Variables, Functions.

Download the fla containing these examples (zipped)


Page 1 of 2
Tutorial details:
Written by: Neil Webb (aka Mortimer Jazz) [email:neilwebb@bigfoot.com] | www.nwebb.co.uk
Time: 40 Minutes
Difficulty Level: Intermediate
Requirements: Flash 5, Flash MX
Topics Covered: Nested Loops
Assumed knowledge: For-loops, Variables, Functions.

Download the fla containing these examples (zipped)

Most people know how to use loops, but surprisingly few people realize the power of nested loops. This tutorial aims to give you a solid understanding of how they work and ideas for how they can be used in your Flash movies. If you don't know how to use a for loop then read Jesse's tutorial on Scripted Loops first. That will get you up to speed. This tutorial should be especially useful as a precursor to beginning XML, but then loops are useful for pretty much anything!

So what's the big deal about nested loops then? Well, the big deal lies with the order in which they execute.
It makes for a very powerful way of sorting through data, by breaking it down in to smaller and smaller chunks, but first things first...
There are two common ways of writing nested loops. One way is to 'bury' loops inside each other like this:

[as]//------nested loops-------
//outer loop
for (i=0; i<2; i++){
        trace("outerloop");
        //inner loop
        for(j=0; j<2; j++){
                trace("innerloop");
        }
}
[/as]

The other, my personal preference for reasons of clarity, is to put each loop inside a function and call the second loop from inside the first loop - like so:

[as]myLoop1();//call the first function

function myLoop1(){
        for(i=0; i<2; i++){
                trace("loop1");
                myLoop2();//call the second loop from within the first loop
        }
}

function myLoop2(){
        for(j=0; j<2; j++){
                trace("loop2");
        }
}
[/as]

If you haven't done so already, copy and paste the second example into an empty frame in a new movie (or download the fla, and uncomment the first example), run the movie and let's have a look at what those traces sent to the output window...

Okay, this is the order we get: loop1, loop2, loop2, loop1, loop2, loop2

Notice the order in which the loops execute, it may not be as you expected.
Both loops are told to execute twice, so how come it didn't just go loop1, loop2, loop1, loop2 ?

Well, it's all about loops completing iterations. The word "iterate" simply means to "repeat in sequence". If we created a for-loop and told it to loop twice, we would say that it has two iterations...otherwise programmers would be talking about "the fourth loop of the second loop" and programming doesn't need to be made any more complicated thank you very much! If I talk about "The second iteration of the first loop" then it is so much clearer and you have a chance of understanding what I'm on about!

Loop1 can't finish it's first iteration until it's done everything inside of it. Loop2 is inside of it. Because loop2 doesn't call any other functions or have any nested-loops inside itself it just loops until it's completed as many iterations as it was told to do.

But wait! Loop1 was told to loop twice, and we're still on the first loop. Now that it's finished doing everything inside of it, it can complete it's first iteration and start on the second one. Now the whole process is repeated..... it executes loop2 again, which iterates twice, then loop1 ends. Phew!
Time for an example I think. Here is the same code I used before but now it's got a few added traces so we can see what's happening in our movie:

[as]myLoop1();//call the first function

function myLoop1(){
        for(i=0; i<2; i++){
                trace("loop1");
                myLoop2();//call the second loop from within the first loop
                trace ("finished an iteration of loop 1");
        }
        trace ("finished loop 1");
}

function myLoop2(){
        for(j=0; j<2; j++){
                trace("loop2");
        }
        trace ("finished an iteration of loop 2");
}
[/as]

Take a moment to study the trace output in the output window. That should make it a bit clearer. The first loop calls the second loop (okay, the first function calls the second function, but for the sake of clarity...). So where were we? Oh yes, the first loops calls the second loop. There are no more nestedloops after that so the second loop says "I'm going to loop as many times as I possibly can". When it's done that, the loop before it is checked again to see if it's finished looping too. If it's not then it loops a second time ...calls loop2 again and the whole process is repeated.
Now moving swiftly on, let's look at what happens when we create a third-loop/third-function and call it from within loop2, and then we'll look at a practical application for all this stuff. Yes of course there is a use. You think I'm doing this for fun?

[as]myLoop1();//call the first function

function myLoop1(){
        for(i=0; i<2; i++){
                trace("loop1");
                myLoop2();//call the second loop from within the first loop
        }
        trace ("finished loop 1");
}

function myLoop2(){
        for(j=0; j<2; j++){
                trace("loop2");
                myLoop3();//call the second loop from within the first loop
        }
        trace ("finished loop 2");
}

function myLoop3(){
        for(p=0; p<2; p++){
                trace("loop3");
        }
        trace ("finished loop 3");
}
[/as]

So in essence it goes: 1,2,3,3,2,3,3......1,2,3,3,2,3,3 etc.
That's all very well, but how is it useful to you? Okay, well a good real-world analogy is that of sorting out a deck of playing cards.
If someone asked you to take an ordinary pack of shuffled cards and then sort them in to suits, and then sort all of those suits in to numerical order you'd probably tell them exactly where they can stick their cards and wander off down the pub.

Page 2 of 2

What if you were told to sort them in to suits, and then give them to your friend who would sort each suit in to numerical order? That's not so bad. What order did those functions fire-off in again?!
Hang on, this cheeky person now wants you to sort two packs of cards! Why I oughtta!
Okay, let's return to our code, but this time we'll change the trace outputs. Very-little code is being changed here, but just look at what happens! Yep there's been a lot of code in this tutorial so far but just have a look at the trace outputs for this next example and everything will fall into place!

[as]myLoop1();//call the first function

function myLoop1(){
        for(i=1; i<3; i++){
                trace("person one passes a deck of cards to person two");
                myLoop2();//call the second loop from within the first loop
        }
        trace ("finished deck");
}

function myLoop2(){
        for(j=1; j<5; j++){
                trace("__person two passes suit " + j +"/4 from deck " + i + " to person 3");
                myLoop3();//call the second loop from within the first loop
        }
        trace ("_finished sorting suit " + (j-1) + " of deck " + i);
}

function myLoop3(){
        for(p=1; p<13; p++){
                trace("______person three sorts card number " + p + "/12 from deck " + i+ ", suit " + j );
        }
        trace ("_finished sorting cards from suit " + j);
}
[/as]

Is that spanky or what! ...and all I really did was change/add some traces.
[The eagle-eyed amongst you will have noticed that I changed the loop values for each loop too. We had two decks of cards, so the loop in function 1 had to iterate twice. There are four suits in every deck so function 2's loop had to iterate four times, and there are twelve cards in each suit so the last loop had to iterate twelve times. I also started my variables off at 1 rather than 0 to make the output easier to read]. Here's a bit of our output:

That's a lot of sorting(!) yet all we did was to tell each little loop to do it's bit, bite off a chunk of data, process it and then pass it on.
It works in reverse too, very much like a car assembly line.
Throw a bit of data at function1, it adds something (or calculates something) and passes the finished result to function2, and so on.

If you've ever seen or used XML you will know that it has a tree-structure, as does your folder-view in Windows Explorer (PC users: press the windows key and 'e' to bring up Windows Explorer). Let's have a look at them both. For Windows Explorer you will see something like this:

windows explorer screen shot

I have a CD in my drive. The CD is full of folders and in each folder I have files. Well that makes it much easier for me to find the movie I was looking for, because they are all grouped in a folder with the sensible name "movies".
XML is based on the same organisation principle:

example of XML code

You can see from the indentation of the code and the minus symbols that some items are 'contained' within others, they are grouped in a sensible way. There are three chapters but luckily they're all grouped within "chapters" so they're easy to find, and everything is contained within the book tags.
Hey I've got an idea...say I wanted to let the user retrieve all the chapter-titles for my book? Well, what if we pass the whole book to function 1, which in turn passes each chapter to function 2, which passes each chapter-title to function 3.......

I hope you're starting to see just how powerful all this can be. I've tried to keet this tutorial as generic as possible because loops can be used for so many things, not just sorting data, and I didn't want to get bogged down explaining strings or maths functions.....
What you do inside those loops and how many nesting levels you have is pretty much up to you. I'm sure you can find many more uses. Enjoy :)