Yes. This can be performed by recursive programming.
I assume you do not like to WRITE DOWN these nested for's in source code - as in your example, because this is really ugly programming - like the commentors explain.
The following (pseudo Java-like) code illustrates it. I assume a fixed depth for the nesting. Then you actually like to loop over an integer vector of dimension depth.
int[] length = new int[depth];
int[] counters = new int[depth];
The array counters has to be initialised to 0 (Arrays.fill(counters,0)). The array length has to be initialised to the number of iterations for the respective for loop.
I assume that you like to perform a certain operation within the inner loop. I will call this
performOperation(int[] counters);
- it depends on the multi-dimensional counter, i.e. the counters of the outer for's.
Then you can run the nested for loops by calling
nestedLoopOperation(counters, length, 0);
where
void nestedLoopOperation(int[] counters, int[] length, int level) {
if(level == counters.length) performOperation(counters);
else {
for (counters[level] = 0; counters[level] < length[level]; counters[level]++) {
nestedLoopOperation(counters, length, level + 1);
}
}
}
In your case your System.out.println() would be
performOperation(int[] counters) {
String counterAsString = "";
for (int level = 0; level < counters.length; level++) {
counterAsString = counterAsString + counters[level];
if (level < counters.length - 1) counterAsString = counterAsString + ",";
}
System.out.println(counterAsString);
}
Answer from Christian Fries on Stack OverflowYes. This can be performed by recursive programming.
I assume you do not like to WRITE DOWN these nested for's in source code - as in your example, because this is really ugly programming - like the commentors explain.
The following (pseudo Java-like) code illustrates it. I assume a fixed depth for the nesting. Then you actually like to loop over an integer vector of dimension depth.
int[] length = new int[depth];
int[] counters = new int[depth];
The array counters has to be initialised to 0 (Arrays.fill(counters,0)). The array length has to be initialised to the number of iterations for the respective for loop.
I assume that you like to perform a certain operation within the inner loop. I will call this
performOperation(int[] counters);
- it depends on the multi-dimensional counter, i.e. the counters of the outer for's.
Then you can run the nested for loops by calling
nestedLoopOperation(counters, length, 0);
where
void nestedLoopOperation(int[] counters, int[] length, int level) {
if(level == counters.length) performOperation(counters);
else {
for (counters[level] = 0; counters[level] < length[level]; counters[level]++) {
nestedLoopOperation(counters, length, level + 1);
}
}
}
In your case your System.out.println() would be
performOperation(int[] counters) {
String counterAsString = "";
for (int level = 0; level < counters.length; level++) {
counterAsString = counterAsString + counters[level];
if (level < counters.length - 1) counterAsString = counterAsString + ",";
}
System.out.println(counterAsString);
}
I created this program to show all the different possible combination of cards (non repeating). It uses recursive for loops. Maybe it can help you.
//I'm lazy, so yeah, I made this import...
import static java.lang.System.out;
class ListCombinations {
//Array containing the values of the cards
static Symbol[] cardValues = Symbol.values();
//Array to represent the positions of the cards,
//they will hold different card values as the program executes
static Symbol[] positions = new Symbol[cardValues.length];
//A simple counter to show the number of combinations
static int counter = 1;
/*Names of cards to combine, add as many as you want, but be careful, we're
talking about factorials here, so 4 cards = 24 different combinations (4! = 24),
but 8 cards = 40320 combinations and 13 cards = 6.23 billion combinations!*/
enum Symbol {
AofSpades, TwoofSpades, ThreeofSpades, FourofSpades
}
public static void main(String args[]) {
//I send an argument of 0 because that is the first location which
//we want to add value to. Every recursive call will then add +1 to the argument.
combinations(0);
}
static void combinations(int locNumber) {
/* I use a recursive (repeating itself) method, since nesting for loops inside
* each other looks nasty and also requires one to know how many cards we will
* combine. I used 4 cards so we could nest 4 for loops one after another, but
* as I said, that's nasty programming. And if you add more cards, you would
* need to nest more for loops. Using a recursive method looks better, and gives
* you the freedom to combine as many cards as you want without changing code. */
//Recursive for loop nesting to iterate through all possible card combinations
for(int valueNumber = 0; valueNumber < cardValues.length; valueNumber++) {
positions[locNumber] = cardValues[valueNumber];
if (locNumber < (cardValues.length-1)) {
combinations(locNumber + 1);
}
//This if statement grabs and displays card combinations in which no card value
// is repeated in the current "positions" array. Since in a single deck,
// there are no repeated cards. It also appends the combination count at the end.
if (locNumber == (cardValues.length-1) && repeatedCards(positions)) {
for (int i = 0; i < cardValues.length; i++) {
out.print(positions[i]);
out.print(" ");
}
out.printf("%s", counter);
counter++;
out.println();
}
}
}
static boolean repeatedCards(Symbol[] cards) {
/*Method used to check if any cards are repeated in the current "positions" array*/
boolean booleanValue = true;
for(int i = 0; i < cardValues.length; i++) {
for(int j = 0; j < cardValues.length; j++) {
if(i != j && cards[i] == cards[j]) {
booleanValue = false;
}
}
}
return booleanValue;
}
}
java - Nested Loop Recursion - Stack Overflow
Arbitrary depth nested for-loops without recursion - Computer Science Stack Exchange
algorithms - General way to convert a loop (while/for) to recursion or from a recursion to a loop? - Software Engineering Stack Exchange
c - Convert nested loop to recursion - Stack Overflow
Videos
Hey guys, I'm pretty new to python and I'd like to practice using Recursion in my code to further assist my understandings with the recursive function. From what I am aware of, identifying a base case is required to prevent infinite recursion but I cannot seem to figure out the base case for this scenario.
Simplified code as shown below:
for y in range(N):
for x in range(M):
if origin[x][y] == 1 and CellsMap[x][y] == 0:
CellsCounter += 1
DiscoverCells(origin, x, y, CellsCounter) Basically the above code will scan for every (x, y) coordinate in a grid (Implemented by the nested For Loop)
How do I go about converting this code into recursion, with a call to function of def DiscoverCells()?
Thanks in advance!!
Have a look at your loops, i.e. how they are related to each other. As an example let's take the 1st and 2nd:
for (int a = 0; a < N; a++) {
for (int b = a + 1; b < N; b++) {
As you can see each loop uses 3 values/variables:
- the loop variable (
a,b), let's call itx - the maximum value
N - an initial value (
0,a + 1), let's call itstart
Thus both loops could be rewritten as
for (int x = start; x < N; x++ ) { ... }
Now put that into a method and add a condition for the recursion:
void runInnerLoop( int start, int N) {
for (int x = start; x < N; x++ ) {
runInnerLoop( x + 1, N );
}
}
Note that in your case you'd need to also pass the list of strings as a parameter and add a string to it, either before of after the recursion.
Also note that I didn't include any additional check whether to do the recursive call or not. That way you'd eventually end up with start == N but the loop condition would take take of that. Adding a condition like if( x < N - 1 ) would prevent an unnecessary recursive call at the cost of additional condition evaluation. Which option would be faster remains to be seen but since that's probably not really relevant I'd opt for the easier to read version.
However, since you're current learing recursion: keep in mind to always check whether the abort condition can be reached in all cases or not. Otherwise you'd run into StackOverflowError etc. - which could also happen if your N is too big in which case you'd need a different approach.
Edit:
I must admit that I overlooked a piece of information in your question, i.e. there is a limited recursion depth which you called M. Thus I'll expand my answer with that information and I'll also explain how to get the "lists" you want to print.
Basically handling the recursion depth is easy: you pass the current depth + 1 to each call as well as the maximum depth and before doing a recursive call you check for depth < maxDepth - if this is true you do a recursice call, if it is false you print the current branch (i.e. the "list" of integers).
Handling the lists isn't that hard but doing it efficiently requires some thought. Basically each iteration adds a new list, i.e. 0,1,2 and 0,2,3 are different lists.
If you'd use lists you'd have to pass the current list to the recursive call and inside the loop create a new list, add all the values of the top list to it and finally add the current loop variable to it (e.g. List<Integer> list = new ArrayList<>( topList ); list.add(x);).
However, you only need the lists in the deepst calls, i.e. when printing or collecting them. This means all those intermediate lists are a waste of time and memory. So instead you might want to use a Stack to track the current loop values, i.e. at the start of an iteration you push the current value to the stack and remove the top value at the end of the iteration. That way you can reuse the same stack and print only the current loop variables (or collect them into a new list for later use).
Here's the top example using recursion depth and a stack:
void runInnerLoop( int start, int N, int depth, int maxDepth, Stack<Integer> stack) {
for (int x = start; x < N; x++ ) {
stack.push( x ); //add the current value to the stack
if( depth < maxDepth ) { //max depth not reached, do another recursion
runInnerLoop( x + 1, N, depth + 1, maxDepth, stack );
} else {
System.out.println( stack ); //max depth reached, print now
}
stack.pop(); //remove the top value from the stack
}
}
The inital call for your first example (N=4, maxDepth=3) would look like this:
runInnerLoop( 0, 4, 1, 3, new Stack<>() );
Update 4
static List<List<Integer>> f(int init, int N, int depth, List<Integer> ls) {
List<List<Integer>> all = new ArrayList<>();
for(int i = init; i < N; i++) {
List<Integer> ls_ = new ArrayList<Integer>();
ls_.addAll(ls);
ls_.add(i);
if(depth == 0) {
all.add(ls_);
} else {
all.addAll(f(i + 1, N, depth-1, ls_));
}
}
return all;
}
Original
Without spoiling too much maybe this helps you:
for (int i = 0; i < 10; i++)
System.out.println(i);
is semantically the same as:
public static void f(final int i) {
if (i < 10) {
System.out.println(i);
For.f(i + 1);
}
}
You will also notice that:
while(i < 10) {
System.out.println(i);
i++;
}
is basically the same thing and can be translated to recursion the same way.
I wouldn't recommend coding like this but you can rewrite every for-loop to a recursive function this way. for loops don't consume as much stack space.
When you nest for loops you can translate them using the same algorithm:
for (int x = 0; x < 3; x++)
for (int y = 0; y < 3; y++)
System.out.println(x + "," + y);
becomes two functions f,g:
public static void f(final int x) {
if (x < 3) {
For.g(x, 0);
For.f(x + 1);
}
}
public static void g(final int x, final int y) {
if (y < 3) {
System.out.println(x + "," + y);
For.g(x, y + 1);
}
}
Update
To answer the comments:
It doesn't matter how many for-loops you have nested. Every for-loop can be rewritten as a recursive function. If you have N nested for-loops you can rewrite them to N recursive functions. The method is as follow:
If you have for(TYPE i = INIT; CONDITION; P-EXPRESSION) { CODE } you can translate it to:
function NAME(TYPE i) {
if(CONDITION) {
CODE
P-EXPRESSION
NAME(i); //this is the recursive call
}
}
NAME(INIT)
If you have nested for-loops the method is the same but you have to pass local variables as parameters.
for(int a = INIT_A; CONDITION_A; P-EXPRESSION_A) {
CODE_A
for(int b = INIT_B; CONDITION_B; P-EXPRESSION_B) {
CODE_B
//^- if you use a in this you have to pass a as a parameter
for(int c = INIT_C; CONDITION_C; P-EXPRESSION_C) {
CODE_C
//^- same deal
}
}
}
Becomes roughly (pseudo-code):
function f(int a) {
if(CONDITION_A) {
CODE_A
g(a, INIT_B);
P-EXPRESSION_A
f(a);
}
}
function g(int a, int b) {
if(CONDITION_B) {
CODE_B
h(a,b, INIT_C);
P-EXPRESSION_B
g(a, b);
}
}
function h(int a, int b, int c) {
if(CONDITION_C) {
CODE_C
P-EXPRESSION_C
h(a,b,c);
}
}
f(INIT_A)
Update 2
The direct 1:1 translation using the above method gives you:
public static List<String> f(int a, int N, List<String> stringList) {
if(a < N) {
g(a, a + 1, N, stringList);
f(a + 1, N, stringList);
}
return stringList;
}
public static List<String> g(int a, int b, int N, List<String> stringList) {
if(b < N) {
h(a, b, b+1, N, stringList);
g(a, b+1, N, stringList);
}
return stringList;
}
public static List<String> h(int a, int b, int c, int N, List<String> stringList) {
if(c < N) {
String str = " ( " + Integer.toString(a)
+ " , " + Integer.toString(b)
+ " , " + Integer.toString(c) +" ) ";
stringList.add(str);
h(a, b, c+1, N, stringList);
}
return stringList;
}
It's not beautiful/optimal code but it's a translation of each for-loop to a recursive function.
Update 3
A nicer translation would have the form:
h a b c n
|c < n = (a,b,c) : h a b (succ c) n
|otherwise = []
g a b n
|b < n = h a b (succ b) n ++ g a (succ b) n
|otherwise = []
f a n
|a < n = g a (succ a) n ++ f (succ a) n
|otherwise = []
main = print $ f 0 4
but this would translate to java as:
public static List<String> f(int a, int N) {
if(a < N) {
List<String> ls = new ArrayList<String>();
ls.addAll(g(a, a + 1, N));
ls.addAll(f(a + 1, N));
return ls;
}
return new ArrayList<String>();
}
public static List<String> g(int a, int b, int N) {
if(b < N) {
List<String> ls = new ArrayList<String>();
ls.addAll(h(a,b,b+1,N));
ls.addAll(g(a,b+1,N));
return ls;
}
return new ArrayList<String>();
}
public static List<String> h(int a, int b, int c, int N) {
if(c < N) {
String str = " ( " + Integer.toString(a)
+ " , " + Integer.toString(b)
+ " , " + Integer.toString(c) +" ) ";
List<String> ls = new ArrayList<String>();
ls.add(str);
ls.addAll(h(a,b,c+1,N));
return ls;
}
return new ArrayList<String>();
}
Which is not efficient Java :).
Actually you should break the function down first:
A loop has a few parts:
the header, and processing before the loop. May declare some new variables
the condition, when to stop the loop.
the actual loop body. It changes some of the header's variables and/or the parameters passed in.
the tail; what happens after the loop and return result.
Or to write it out:
foo_iterative(params){
header
while(condition){
loop_body
}
return tail
}
Using these blocks to make a recursive call is pretty straightforward:
foo_recursive(params){
header
return foo_recursion(params, header_vars)
}
foo_recursion(params, header_vars){
if(!condition){
return tail
}
loop_body
return foo_recursion(params, modified_header_vars)
}
Et voilà; a tail recursive version of any loop. breaks and continues in the loop body will still have to be replaced with return tail and return foo_recursion(params, modified_header_vars) as needed but that is simple enough.
Going the other way is more complicated; in part because there can be multiple recursive calls. This means that each time we pop a stack frame there can be multiple places where we need to continue. Also there may be variables that we need to save across the recursive call and the original parameters of the call.
We can use a switch to work around that:
bar_recurse(params){
if(baseCase){
finalize
return
}
body1
bar_recurse(mod_params)
body2
bar_recurse(mod_params)
body3
}
bar_iterative(params){
stack.push({init, params})
while(!stack.empty){
stackFrame = stack.pop()
switch(stackFrame.resumPoint){
case init:
if(baseCase){
finalize
break;
}
body1
stack.push({resum1, params, variables})
stack.push({init, modified_params})
break;
case resum1:
body2
stack.push({resum2, params, variables})
stack.push({init, modified_params})
break;
case resum2:
body3
break;
}
}
}
Following up on @ratchet freak's answer, I created this example of how the Fibonacci function can be rewritten to a while loop in Java. Note that There's a much simpler (and efficient) way to rewrite the Fibonacci with a while loop though.
class CallContext { //this class is similar to the stack frame
Object[] args;
List<Object> vars = new LinkedList<>();
int resumePoint = 0;
public CallContext(Object[] args) {
this.args = args;
}
}
static int fibonacci(int fibNumber) {
Deque<CallContext> callStack = new LinkedList<>();
callStack.add(new CallContext(new Object[]{fibNumber}));
Object lastReturn = null; //value of last object returned (when stack frame was dropped)
while (!callStack.isEmpty()) {
CallContext callContext = callStack.peekLast();
Object[] args = callContext.args;
//actual logic starts here
int arg = (int) args[0];
if (arg == 0 || arg == 1) {
lastReturn = arg;
callStack.removeLast();
} else {
switch (callContext.resumePoint) {
case 0: //calculate fib(n-1)
callStack.add(new CallContext(new Object[]{arg - 1}));
callContext.resumePoint++;
break;
case 1: //calculate fib(n-2)
callContext.vars.add(lastReturn); //fib1
callStack.add(new CallContext(new Object[]{arg - 2}));
callContext.resumePoint++;
break;
case 2: // fib(n-1) + fib(n-2)
callContext.vars.add(lastReturn); //fib2
lastReturn = (int) callContext.vars.get(0) + (int) callContext.vars.get(1);
callStack.removeLast();
break;
}
}
}
return (int) lastReturn;
}
A loop like:
for (int i=0; i<n; i++) {
func(i);
}
can be translated to recursion as:
void rec_fun(int i,int n) {
if (!(i<n)) return;
func(i);
rec_fun(i+1,n);
}
...
rec_fun(0,n);
So:
for (i = 0; i < q; i++) { // I have convert this to recursion.
for (j = 0; j < p; j++) {
for (k = 0; k < r; k++) {
if (b[i] >= a[j] && b[i] >= c[k]) {
sum += f(a[j], b[i], c[k]);
}
}
}
}
can be translated as:
void rec_k(int k,int r,int i,int j) { // k-loop
if (!(k<r)) return;
if (b[i] >= a[j] && b[i] >= c[k]) {
sum += f(a[j], b[i], c[k]);
}
rec_k(k+1,r,i,j); // recurse
}
void rec_j(int j,int p,int i,int r) { // j-loop
if (!(j<p)) return;
rec_k(0,r,i,j); // inner loop
rec_j(j+1,p,i,r); // recurse
}
void rec_i(int i,int q,int p,int r) { // i-loop
if (!(i<q)) return;
rec_j(0,p,i,r); // inner loop
rec_i(i+1,q,p,r); // recurse
}
...
rec_i(0,q,p,r);
I'm not sure this is either more readable or useful, but it meets your initial needs.
Let us assume that the intention of this code is to only calculate the sum.
You can make a function as
int recurse_sum(int i, int j, int k) {
int res = .... // Logic for calculating sum for these indices i, j, k.
k++;
if (k==r) {
k = 0;
j++;
}
if(j==p){
j=0;
i++;
}
if(i==q){
return res;
}
return res + recurse_sum(i,j,k);
}
Now you can just call with recurse_sum(0,0,0);
The rest of the parameters can either be made global or just passed along with i,j,k.
I hope this helps.
Edit:
As mentioned by @dlasalle this code can be made open to tail call recursion optimization by placing the call at the end of the function.
In that case you can have the following version.
int recurse_sum(int i, int j, int k, int sum) {
int res = .... // Logic for calculating sum for these indices i, j, k.
k++;
if (k==r) {
k = 0;
j++;
}
if(j==p){
j=0;
i++;
}
if(i==q){
return res + sum;
}
return recurse_sum(i,j,k,res+sum);
}
Here the function ends with returning the value from the inner call and hence can be easily optimized.
Ofcourse in this case it will have to be called as recurse_sum(0,0,0,0);
This maybe
def do_step(item, position_dict, depth):
print position_dict
if depth > 0:
new_positions = available_pos(item, position_dict)
for (x, y) in new_positions:
position_dict[item] = (x, y)
for next_item in ['a', 'b', 'c', 'd']:
do_step(next_item, position_dict.copy(), depth - 1)
You call do_step('a', position_dict.copy(), 10). position_dict was given.
This is the non-functional version which should run faster
def do_step(item, position_dict, depth):
print position_dict
if depth > 0:
old_position = position_dict[item]
new_positions = available_pos(item, position_dict)
for (x, y) in new_positions:
position_dict[item] = (x, y)
for next_item in ['a', 'b', 'c', 'd']:
do_step(next_item, position_dict, depth - 1)
# Restore the old position
position_dict[item] = old_position
Recursion is the way to go here. Since you're doing the same thing multiple times, it's only natural to write a function to do it.
Let's start with a non-recursive function. It could look like this:
def update_pos(item):
ava1 = available_pos(item, position_dict)
for a in ava1:
position_dict[item] = a
# but now what? we need to update the next item's location
This updates 1 item's position, so the next step is to make it update multiple items' positions. So instead of passing a single item, we'll pass it a list of items.
def update_pos(items_): # I called it items_ to avoid a name clash with the global items list
item= items_[0]
ava1 = available_pos(item, position_dict)
for a in ava1:
position_dict[item] = a
#recursively update the remaining items' positions
if len(items_) > 1:
update_pos(items_[1:])
All that's left to do now is to actually produce a result:
def update_pos(items_):
item= items_[0]
ava1 = available_pos(item, position_dict)
for a in ava1:
position_dict[item] = a
#recursively update the remaining items' positions
if len(items_) > 1:
update_pos(items_[1:])
else:
pos.append([position_dict[i] for i in items])
I didn't test this code, but it should at least give you an idea how to solve your problem.
First, always pass arrays in, methods usually shouldn't do this sort of input validation in JavaScript. Also don't throw in calculateStatsForMetric, if you have throwing code there wrap it in a try/catch and return a falsey value.
Now, you can use higher order array methods like flatMap and map:
- Take each metric
- For each metric
- Take each stat (this calls for a flatMap on a map)
- Calculate a function on it
- Keep truthy values (this calls for a filter)
Or in code:
export const refactored = (measure, metrics, stats) =>
metrics.flatMap(metric => stats.map(stat => ({
metric,
stat,
value: calculateStatsForMetric(stat, metric, measure)
}))).filter(o => o.value);
A simple approach would be to use forEach -
let statistics = [];
metrics.forEach(m => {
stats.forEach(s => {
let value = calculateStatsForMetric(s, m, measures);
if (value) {
statistics.push({
metric: m,
stat: s,
value: value
});
}
});
});
You have a single little error in your code:
You call a recursive function from your i + 1, but not your index + 1.
It causes index to be equal not current array index but it's value.
For example, when you passed [0, 1, 2], your data now is [0, 1] and you are about to insert 3, you call loop(3 + 1), index 4 goes out of an array range. if (index === end) condition fails and it doesn't output. for (var i = index; i < len; i++) loop fails as well, and everything is going wrong.
It should be:
var len = 4;
var end = 3;
var data = [];
var loop = function (index) {
if (index === end) {
console.log(data);
return;
}
for (var i = index; i < len; i++) {
data[index] = i;
loop(index + 1); // <--- HERE
}
}
loop(0);
Here is the working JSFiddle demo.
Update:
Oh, now I see. You need a[i] > a[i-1] condition to be true for all combinations. Just add a start variable which will save the last inserted value in order to comply with this rule.
var len = 4;
var end = 3;
var data = [];
var loop = function (start, index) {
if (index === end) {
document.body.innerHTML += "<br/>" + data;
return;
}
for (var i = start; i < len; i++) { // We start from 'start' (the last value + 1)
data[index] = i;
loop(i + 1, index + 1); // Here, we pass the last inserted value + 1
}
}
loop(0, 0); // At beginning, we start from 0
Updated JSFiddle demo with passing argument.
You can check the previous value instead of passing a value as an argument if it looks wrong for you. Condition will be like "if it is a first number, start from 0; else - start from the next number after the previous one".
var start = (index === 0 ? 0 : data[index-1] + 1);
Updated JSFiddle demo with calculating start.
There are a couple of errors; you are recursing starting from i+1 instead of index+1 and you are counting from index instead of counting from data[index-1]+1.
The corrected version is:
var len = 4;
var end = 3;
var data = [];
var loop = function (index) {
if (index === end) {
console.log(data);
return;
}
for (var i = (index==0 ? 0 : data[index-1]+1); i < len; i++) {
data[index] = i;
loop(index + 1);
}
}
This is not a recursion problem, it's an "async problem." Your issue is that NodeJS access memcached asynchronously and your procedural style code does not. So, you need to think about the problem differently.
function getMemcacheData(key, data)
{
DB.get(key, function(err, result)
{
if (err) return false;
data[ key ] = result;
})
}
var oData = {};
for (var x = startX; x <= endX; x++)
{
for (var y = startY; y <= endY; y++)
{
var key = x + "_" + y;
getMemcacheData(key, oData);
}
}
That will work, but - you have another problem then. You have no way of knowing when your MemcacheD data has been loaded into oData, you just have to sit and wait and guess. There are ways to deal with this; but my favorite way is to use a library named async.
With async, you could do this:
var syncStack = [],
oData = {};
for (var x = startX; x <= endX; x++)
{
for (var y = startY; y <= endY; y++)
{
(function(key)
{
syncStack.push(function(callback)
{
DB.get(key, function(err, result)
{
/** If you don't care about data not being loaded
you do this: */
if (!err)
{
data[ key ] = result;
}
callback();
/** If you do care, and you need to terminate if
you don't get all your data, do this: */
if (err)
{
callback(err);
return false;
}
data[ key ] = result;
callback();
})
});
})(x + "_" + y);
}
}
async.parallel(syncStack, function(error)
{
//this is where you know that all of your memcached keys have been fetched.
//do whatever you want here.
//if you chose to use the 2nd method in the fetch call, which does
//"callback(error)" error here will be whatever you passed as that
//err argument
});
What this code is actually doing is creating an array of functions, each of which calls the Db.get method for a specific key, and adds the result to the oData variable.
After the array of functions is created, we use the async library's parallel method, which takes an array of functions and calls them all in parallel. This means that your code will send a bunch of requests off to memcached to get your data, all at once. When each function is done, it calls the callback function, which tells the async lib that the request finished. When all of them are finished, async calls the callback closure you supplied as the 2nd argument in the call to the parallel method. When that method is called, you either know A. something went wrong, and you have the error to recover from it or B. all requests are finished, and you may or may not have all the data you requested (expired or stale keys requested, or whatever). From there, you can do whatever you want, knowing you have finished asking for all the keys you needed.
I hope this helps.
parallel get:
function loadPoints(cb)
{
var oData = {};
for( x = startX; x <= endX; x++ )
{
for( y = startY; y <= endY; y++ )
{
var key = x + '_' + y;
num_points++;
Db.get(key, function(err, val) {
if (err)
return cb(err);
oData[key] = val;
num_points--;
if (num_points === 0)
cb(null, oData);
});
}
}
}
sequential get:
function loadPoints(cb)
{
var oData = {};
function loadPoint(x, y)
{
var key = x + '_' + y;
Db.get(key, function(err, val) {
if (err)
return cb(err);
oData[key] = val;
if (x + 1 < endX)
return loadPoint(x + 1, y);
else if (y + 1 < endY)
return loadPoint(startX, y+1);
else
cb(null, oData);
});
}
loadPoint(startX, startY);
}