簡體   English   中英

如何將嵌套的for循環轉換為遞歸?

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

我從Memcached獲得了一些數據,但是nodejs的異步完全讓我無法理解。 我想把所有結果都放到一個對象中。

這就是我通常會做的事情:

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

但我無法弄清楚如何

Db.get()函數需要一個鍵和一個回調( function(error, result) {}

這只會增加x ..​​....

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

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

這不是遞歸問題,而是“異步問題”。 您的問題是NodeJS異步訪問memcached而您的過程樣式代碼沒有。 所以,你需要以不同的方式思考問題。

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);
    }
}

這會奏效,但是 - 你還有另一個問題。 您無法知道何時將MemcacheD數據加載到oData ,您只需等待並猜測即可。 有辦法解決這個問題; 但我最喜歡的方法是使用名為async的庫。

使用異步,您可以這樣做:

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
});

這段代碼實際上在做的是創建一個函數數組,每個函數都調用特定鍵的Db.get方法,並將結果添加到oData變量中。

在創建函數數組之后,我們使用async庫的parallel方法,該方法接受一系列函數並將它們全部並行調用。 這意味着您的代碼會將一堆請求發送到memcached以獲取您的數據。 當每個函數完成后,它會調用callback函數,該函數告訴async lib請求已完成。 完成所有這些操作后, async調用您在parallel方法調用中作為第二個參數提供的回調閉包。 當調用該方法時,您要么知道A.出錯了,並且您有錯誤要從中恢復或B.所有請求都已完成,您可能擁有或未擁有您請求的所有數據(已過期或請求過期密鑰) , 管他呢)。 從那里,你可以隨心所欲,知道你已經完成了所需的所有鑰匙。

我希望這有幫助。

並行得到:

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);         
       });
    } 
  }
}

順序獲取:

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