While this meditation is about arbitrarily nested loops, it has come as a result of a specific problem I was trying to solve. Please try to focus on the meditation and not the specific problem.
Introduction
Explanation of arbitrarily nested loops
Now imagine that you wanted to do the same thing but you were doing it for your upcoming birthday gifts. Since you won't know until the gifts arrive (runtime) what you are going to receive, you can't pre-construct the loops. You know you may need to extend the number of loops to include things like gloves to cover your hands and hats to cover your head and sunglasses for your eyes.for my $feet ( qw/black brown sneaker/ ) { for my $legs ( qw/shorts dress_pants jeans/ ) { for my $torso ( qw/t-shirt dress_shirt sweater/ ) { print "$torso $legs $feet\n"; } } }
Abritrary nested loops is not knowing in advance the number of loops or the number of items in each loop. It may seem like a difficult problem to solve, but in fact it is quite easy.
How to handle arbitrarily nested loops
Assume that you have received a list of lists that need to be looped through. Each list represents a dial that must be turned. When you the dial you are turning reaches its maximum value, the dial to its left increments by one and the current one rolls over to the start. When the leftmost dial reaches exceeds its maximum number - you know you are finished.
To make this an iterator you need to use closures which I won't cover. Instead of rolling your own you should probably use tye's Algorithm::Loops 'NestedLoops'. There is still value in removing the veil of mystery to understand how it works even if you are not going to implement it yourself.(black, brown, sneakers), (shorts, dress_pants, jeans), (t-shirt, dres +s_shirt, sweater) # Start position 0, 0, 0 = black, shorts, t-shirt 0, 0, 1 = black, shorts, dress_shirt 0, 0, 2 = black, shorts, sweater 0, 1, 0 = black, shorts, t-shirt 0, 1, 1 = black, shorts, dress_shirt 0, 1, 2 = black, shorts, sweater 0, 2, 0 = black, dress_pants, t-shirt ... 2, 2, 2 = sneakers, jeans, sweater
How to dynamically construct the loops
Now it is a simple matter of checking when a dial rolls over to the beginning if the dial was a fixed list or generated from a code ref. If it was from a code ref, replace the current list with the return value of the the executed code ref.
What else might I want?
You might want the ability to filter out some of the results. We may allow the user to pass in a code ref that we will execute at the end of each dial turn. If the code ref returns a true value we return the list and if not, we spin the dial again - wash, rinse, repeat.
You may also want to execute some arbitrary piece of code after each loop. Again, this is as simple as designing your API such that the user can pass in a code ref that you execute at the end of each dial turn.
Conclusion
I didn't want this to be a tutorial showing step by step code for 2 reasons. The first is because there is an existing ready made solution. The second is because one of the best ways to learn is by doing. Try it out, make sure you can do it on your own. You will likely learn something. If you have problems or questions - feel free to reply.
If anyone has the inclination to make this work in C as a reusable library I will be very much interested. See also NestedLoops and the Odometer Model.
Cheers - L~R
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Arbitrarily Nested Loops
by ikegami (Patriarch) on Feb 03, 2006 at 20:53 UTC | |
Re: Arbitrarily Nested Loops
by ikegami (Patriarch) on Feb 03, 2006 at 16:44 UTC | |
Re: Arbitrarily Nested Loops
by thor (Priest) on Feb 03, 2006 at 17:17 UTC | |
by Limbic~Region (Chancellor) on Feb 03, 2006 at 17:35 UTC | |
Re: Arbitrarily Nested Loops
by dokkeldepper (Friar) on Feb 07, 2006 at 12:08 UTC | |
Re: Arbitrarily Nested Loops
by radiantmatrix (Parson) on Feb 07, 2006 at 15:38 UTC |