简体   繁体   English

如何将嵌套的for循环转换为递归?

[英]How to convert a nested for-loop to a recursion?

I get some data from a Memcached, but the asynchrony of nodejs completely eludes me. 我从Memcached获得了一些数据,但是nodejs的异步完全让我无法理解。 I want to put all the results into an object. 我想把所有结果都放到一个对象中。

This is what I would do normally: 这就是我通常会做的事情:

for( x = startX; x <= endX; x++ )
{
  for( y = startY; y <= endY; y++ )
  {
    oData[ x + '_' + y ] = Db.get( x + '_' + y );
  } 
}

But I can't figure out how 但我无法弄清楚如何

The Db.get() function wants a key and a callback ( function(error, result) {} ) Db.get()函数需要一个键和一个回调( function(error, result) {}

This would just increment the x... 这只会增加x ..​​....

var onGet = function (error, result)
{
  x++;
  if(!error && result !== null) 
  {
    oData[ x + '_' + y ] = result
  }
};

Db.get(x + '_' + y, onGet);

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. 您的问题是NodeJS异步访问memcached而您的过程样式代码没有。 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. 您无法知道何时将MemcacheD数据加载到oData ,您只需等待并猜测即可。 There are ways to deal with this; 有办法解决这个问题; but my favorite way is to use a library named async . 但我最喜欢的方法是使用名为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. 这段代码实际上在做的是创建一个函数数组,每个函数都调用特定键的Db.get方法,并将结果添加到oData变量中。

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. 在创建函数数组之后,我们使用async库的parallel方法,该方法接受一系列函数并将它们全部并行调用。 This means that your code will send a bunch of requests off to memcached to get your data, all at once. 这意味着您的代码会将一堆请求发送到memcached以获取您的数据。 When each function is done, it calls the callback function, which tells the async lib that the request finished. 当每个函数完成后,它会调用callback函数,该函数告诉async lib请求已完成。 When all of them are finished, async calls the callback closure you supplied as the 2nd argument in the call to the parallel method. 完成所有这些操作后, async调用您在parallel方法调用中作为第二个参数提供的回调闭包。 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). 当调用该方法时,您要么知道A.出错了,并且您有错误要从中恢复或B.所有请求都已完成,您可能拥有或未拥有您请求的所有数据(已过期或请求过期密钥) , 管他呢)。 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM