最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - execute javascsript for loop alternately forward and backward - Stack Overflow

programmeradmin2浏览0评论

UPDATED BELOW

What I'm trying to do is iterate through an array in chunks, alternating the direction of iteration from chunk to chunk. Confused? So am I. For example, if I want to loop thru an array with 25 elements, but I want to do it in this order: 0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14, 19, 18, 17, 16, 15, 20, 21, 22, 23, 24, what would be the most efficient way of doing this? I'm looking for something scalable because the array I'm working with now is actually 225 elements and I want to traverse it in 15 element chunks, but that may change at some point. So far, the only method I've figured out that actually works is to hard-wire the iteration order into a second array and then iterate through that in the normal way to get the indices for the original array. But that sucks. Any help would be greatly appreciated.

@Bergi asked for some sample code. Please don't beat me up too much. I'm still a noob:

function zeroPadNumber(theNumber, thePadding) {
    var thePaddedNumber = thePadding.substring(0, (thePadding.length - theNumber.length)) + theNumber;
    return thePaddedNumber;
}

var thisTile = 225;
var waveLoop = 15;
function mosaicWave() {
    var theStartNum = thisTile;
    for (w = 0; w < 15; w++) {
        var theNum = theStartNum - w;
        var theNumString = String(theNum); 
        var thePaddedNum = zeroPadNumber(theNumString, "000");
        var theImgName = "sm_" + thePaddedNum;
        var theNewSrc = theImgFolder + theImgName + "bg.gif";
        document.images[theImgName].src = theNewSrc;
        thisTile = theNum - 1;
        if (waveLoop < 15) {
            var prevStartTile = theStartNum + 15;
            var thePrevNum = prevStartTile - w;
            var thePrevNumString = String(thePrevNum); 
            var thePrevPaddedNum = zeroPadNumber(thePrevNumString, "000");
            var thePrevName = "sm_" + thePrevPaddedNum;
            var thePrevSrc = theImgFolder + thePrevName + ".gif";
            document.images[thePrevName].src = thePrevSrc;
        }
    }
    if (waveLoop == 1) {
        var lastWave = function() {
            var theStartNum = 15;
            for (c = 0; c < 15; c++) {
                var theNum = theStartNum - c;
                var theNumString = String(theNum); 
                var thePaddedNum = zeroPadNumber(theNumString, "000");
                var theImgName = "sm_" + thePaddedNum;
                var theNewSrc = theImgFolder + theImgName + ".gif";
                document.images[theImgName].src = theNewSrc;
            }
        }
        setTimeout(lastWave, 100);
        waveLoop = 15;
        thisTile = 225;
    } else {
        waveLoop--;
        setTimeout(mosaicWave, 100);
    }
}

This snippet does a different animation. It starts at the lower right corner of the matrix and "turns on" the 15 tiles in the bottom row. then it moves up a row, turns on the tiles in that row and turns off the tiles in the previous row. And so forth until the top row is turned on then off. not very far off really from the top-down serpentine effect I'm trying to achieve in the new function. The reversing order on each row was the main thing stumping me. That being said, any suggestions about optimizing the above code would also be greatly appreciated.

UPDATE 1:

To me, this seems like it should work, but it doesn't. Can anyone spot the problem?

var loopRange = 225;
var blockRange = 15;
var theDirection = 1;
var weaveLoop = 0;

function mosaicWeave() {
    var curObj, curSrc, lastObj, lastSrc;
    var toggleLeadTile = function() {
        alert(curSrc);
        curObj.src = curSrc;
    };
    var toggleLastTile = function() {
        lastObj.src = lastSrc;
    };
    while (weaveLoop < loopRange) {
        imgNum = weaveLoop + 1;
        imgName = "sm_" + zeroPadNumber(String(imgNum), "000");
        if (imgNum < 15) {
            //handle first row
            curObj = document.images[imgName];
            curSrc = theImgFolder + imgName + "bg.gif";
            window.setTimeout(toggleLeadTile, 100);
        } else if (imgNum == 225) {
            //handle last row
            curObj = document.images[imgName].src;
            curSrc = theImgFolder + imgName + "bg.gif";
            window.setTimeout(toggleLeadTile, 100);
            for (i = 211; i < 226; i++) {
                lastImgName = "sm_" + ((weaveLoop + 1) - 15);
                lastObj = document.images[lastImgName];
                lastSrc = theImgFolder + lastImgName + ".gif";
                window.setTimeout(toggleLastTile, 100);
            }
        } else {
            //handle middle rows
            lastImgName = "sm_" + ((weaveLoop + 1) - 15);
            curObj = document.images[imgName];
            curSrc = theImgFolder + imgName + "bg.gif";
            lastObj = document.images[lastImgName];
            lastSrc = theImgFolder + lastImgName + ".gif";
            window.setTimeout(toggleLeadTile, 100);
            window.setTimeout(toggleLastTile, 100);
        }
        if (weaveLoop % blockRange == (theDirection == -1 ? 0 : blockRange - 1)) {
            theDirection *= -1;
            weaveLoop += blockRange;
        } else {
            weaveLoop += theDirection;
        }
    }
}

UPDATE 2:

Thanks for everyone's input. This works:

var resetLoop = 1;
var weaveArray = new Array(225);
var weaveRange = 15, weaveDirection = 1, weaveIndex = 0, wInitLoop = 0;

function mosaicWeave() {
    while (weaveIndex < 225) {
        weaveArray[wInitLoop] = weaveIndex + 1;
        if (weaveIndex % weaveRange == (weaveDirection == -1 ? 0 : weaveRange - 1)) {
            weaveDirection *= -1;
            weaveIndex += weaveRange;
        } else {
            weaveIndex += weaveDirection;
        }
        wInitLoop++;
    }
    mWeaveOn();
}

function mWeaveOff() {
    var theNumString = String(weaveArray[resetLoop - 16]); 
    var theImgName = "sm_" + zeroPadNumber(theNumString, "000");
    document.images[theImgName].src = "images/" + theImgName + ".gif";
    mosaicArray[resetLoop - 1] = 0;
    resetLoop++;
    if (resetLoop < 226) {
        setTimeout(mWeaveOn, 25);
    } else if (resetLoop > 225 && resetLoop <= 240) {
            setTimeout(mWeaveOff, 25);
    } else {
        resetLoop = 1;
    }
}

function mWeaveOn() {
    var theNumString = String(weaveArray[resetLoop - 1]); 
    var theImgName = "sm_" + zeroPadNumber(theNumString, "000");
    document.images[theImgName].src = "images/" + theImgName + "bg.gif";
    mosaicArray[resetLoop - 1] = 1;
    if (resetLoop < 16) {
        resetLoop++;
        setTimeout(mWeaveOn, 25);
    } else {
        setTimeout(mWeaveOff, 25);
    }
}

Does anyone have an opinion on if there is a more efficient way of doing this? Or a heads up on how this might break on different platforms/browsers or under different circumstances? Thanks again.

UPDATED BELOW

What I'm trying to do is iterate through an array in chunks, alternating the direction of iteration from chunk to chunk. Confused? So am I. For example, if I want to loop thru an array with 25 elements, but I want to do it in this order: 0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14, 19, 18, 17, 16, 15, 20, 21, 22, 23, 24, what would be the most efficient way of doing this? I'm looking for something scalable because the array I'm working with now is actually 225 elements and I want to traverse it in 15 element chunks, but that may change at some point. So far, the only method I've figured out that actually works is to hard-wire the iteration order into a second array and then iterate through that in the normal way to get the indices for the original array. But that sucks. Any help would be greatly appreciated.

@Bergi asked for some sample code. Please don't beat me up too much. I'm still a noob:

function zeroPadNumber(theNumber, thePadding) {
    var thePaddedNumber = thePadding.substring(0, (thePadding.length - theNumber.length)) + theNumber;
    return thePaddedNumber;
}

var thisTile = 225;
var waveLoop = 15;
function mosaicWave() {
    var theStartNum = thisTile;
    for (w = 0; w < 15; w++) {
        var theNum = theStartNum - w;
        var theNumString = String(theNum); 
        var thePaddedNum = zeroPadNumber(theNumString, "000");
        var theImgName = "sm_" + thePaddedNum;
        var theNewSrc = theImgFolder + theImgName + "bg.gif";
        document.images[theImgName].src = theNewSrc;
        thisTile = theNum - 1;
        if (waveLoop < 15) {
            var prevStartTile = theStartNum + 15;
            var thePrevNum = prevStartTile - w;
            var thePrevNumString = String(thePrevNum); 
            var thePrevPaddedNum = zeroPadNumber(thePrevNumString, "000");
            var thePrevName = "sm_" + thePrevPaddedNum;
            var thePrevSrc = theImgFolder + thePrevName + ".gif";
            document.images[thePrevName].src = thePrevSrc;
        }
    }
    if (waveLoop == 1) {
        var lastWave = function() {
            var theStartNum = 15;
            for (c = 0; c < 15; c++) {
                var theNum = theStartNum - c;
                var theNumString = String(theNum); 
                var thePaddedNum = zeroPadNumber(theNumString, "000");
                var theImgName = "sm_" + thePaddedNum;
                var theNewSrc = theImgFolder + theImgName + ".gif";
                document.images[theImgName].src = theNewSrc;
            }
        }
        setTimeout(lastWave, 100);
        waveLoop = 15;
        thisTile = 225;
    } else {
        waveLoop--;
        setTimeout(mosaicWave, 100);
    }
}

This snippet does a different animation. It starts at the lower right corner of the matrix and "turns on" the 15 tiles in the bottom row. then it moves up a row, turns on the tiles in that row and turns off the tiles in the previous row. And so forth until the top row is turned on then off. not very far off really from the top-down serpentine effect I'm trying to achieve in the new function. The reversing order on each row was the main thing stumping me. That being said, any suggestions about optimizing the above code would also be greatly appreciated.

UPDATE 1:

To me, this seems like it should work, but it doesn't. Can anyone spot the problem?

var loopRange = 225;
var blockRange = 15;
var theDirection = 1;
var weaveLoop = 0;

function mosaicWeave() {
    var curObj, curSrc, lastObj, lastSrc;
    var toggleLeadTile = function() {
        alert(curSrc);
        curObj.src = curSrc;
    };
    var toggleLastTile = function() {
        lastObj.src = lastSrc;
    };
    while (weaveLoop < loopRange) {
        imgNum = weaveLoop + 1;
        imgName = "sm_" + zeroPadNumber(String(imgNum), "000");
        if (imgNum < 15) {
            //handle first row
            curObj = document.images[imgName];
            curSrc = theImgFolder + imgName + "bg.gif";
            window.setTimeout(toggleLeadTile, 100);
        } else if (imgNum == 225) {
            //handle last row
            curObj = document.images[imgName].src;
            curSrc = theImgFolder + imgName + "bg.gif";
            window.setTimeout(toggleLeadTile, 100);
            for (i = 211; i < 226; i++) {
                lastImgName = "sm_" + ((weaveLoop + 1) - 15);
                lastObj = document.images[lastImgName];
                lastSrc = theImgFolder + lastImgName + ".gif";
                window.setTimeout(toggleLastTile, 100);
            }
        } else {
            //handle middle rows
            lastImgName = "sm_" + ((weaveLoop + 1) - 15);
            curObj = document.images[imgName];
            curSrc = theImgFolder + imgName + "bg.gif";
            lastObj = document.images[lastImgName];
            lastSrc = theImgFolder + lastImgName + ".gif";
            window.setTimeout(toggleLeadTile, 100);
            window.setTimeout(toggleLastTile, 100);
        }
        if (weaveLoop % blockRange == (theDirection == -1 ? 0 : blockRange - 1)) {
            theDirection *= -1;
            weaveLoop += blockRange;
        } else {
            weaveLoop += theDirection;
        }
    }
}

UPDATE 2:

Thanks for everyone's input. This works:

var resetLoop = 1;
var weaveArray = new Array(225);
var weaveRange = 15, weaveDirection = 1, weaveIndex = 0, wInitLoop = 0;

function mosaicWeave() {
    while (weaveIndex < 225) {
        weaveArray[wInitLoop] = weaveIndex + 1;
        if (weaveIndex % weaveRange == (weaveDirection == -1 ? 0 : weaveRange - 1)) {
            weaveDirection *= -1;
            weaveIndex += weaveRange;
        } else {
            weaveIndex += weaveDirection;
        }
        wInitLoop++;
    }
    mWeaveOn();
}

function mWeaveOff() {
    var theNumString = String(weaveArray[resetLoop - 16]); 
    var theImgName = "sm_" + zeroPadNumber(theNumString, "000");
    document.images[theImgName].src = "images/" + theImgName + ".gif";
    mosaicArray[resetLoop - 1] = 0;
    resetLoop++;
    if (resetLoop < 226) {
        setTimeout(mWeaveOn, 25);
    } else if (resetLoop > 225 && resetLoop <= 240) {
            setTimeout(mWeaveOff, 25);
    } else {
        resetLoop = 1;
    }
}

function mWeaveOn() {
    var theNumString = String(weaveArray[resetLoop - 1]); 
    var theImgName = "sm_" + zeroPadNumber(theNumString, "000");
    document.images[theImgName].src = "images/" + theImgName + "bg.gif";
    mosaicArray[resetLoop - 1] = 1;
    if (resetLoop < 16) {
        resetLoop++;
        setTimeout(mWeaveOn, 25);
    } else {
        setTimeout(mWeaveOff, 25);
    }
}

Does anyone have an opinion on if there is a more efficient way of doing this? Or a heads up on how this might break on different platforms/browsers or under different circumstances? Thanks again.

Share Improve this question edited Oct 15, 2012 at 18:21 Stiff Mittens asked Oct 14, 2012 at 8:50 Stiff MittensStiff Mittens 715 bronze badges 0
Add a ment  | 

4 Answers 4

Reset to default 4
var arr = [0,1,2,3,4,5,6,7,8,9,10,11,11,13,14,15,16,17,18,19,20,21,22,23,24],
    i = 0,
    j = arr.length,
    tmp,
    chunk = 5;

while(i < j) {
    tmp = arr.slice(i, i+=chunk);
    if ((i / chunk) % 2 == 0) {
        tmp = tmp.reverse();
    }
    console.log(tmp);
}

​The demo.

This is a flexible solution where you can change the blocksize as you need it.

var index, max = 25;
for (var i = 0; i < max; i++) {
  if (parseInt(i / 5) % 2)
    index = parseInt(i / 5)*5 + 4 - i % 5;
  else
    index = i;
  // use index as array index
  foo(index);
}

Fiddle

If you have always a multiple of five, you could hard code the iteration over five elements and do an outer loop which counts to max/5 and switch to the right hardcoded iteration.

var index, max = 25;
for ( var i=0; i<max/5; i++) {
  if (i%2) {
    foo(i*5+4);
    foo(i*5+3);
    foo(i*5+2);
    foo(i*5+1);
    foo(i*5+0);
  } else {
    foo(i*5+0);
    foo(i*5+1);
    foo(i*5+2);
    foo(i*5+3);
    foo(i*5+4);
  }
}

Fiddle

I guess the simplest and clearest solution would be to nest two loos:

var arr = new Array(25),
    chunksize = 5;
for (var i=0; i<arr.length; i+=chunksize)
    if (i % (chunksize*2))
         for (var j=i+chunksize-1; j>=i; j--)
             exec(j);
    else
         for (var j=i; j<i+chunksize; j++)
             exec(j);

However, you could also go with only one loop and loopcounter. In the right spots (4, 5, 14, 15, …) the direction (increment/decrement) would change and the counter jumps one chunksize (4→9, 5→10, 14→19, …):

var arr = new Array(25),
    chunksize = 5;

var dir = 1,
    i = 0;
while (i<arr.length) {
    exec(i); // or whatever you need to do
    if (i % chunksize == (dir==-1 ? 0 : chunksize - 1)) {
        dir *= -1;
        i += chunksize;
    } else
        i += dir;
}

or, in one for-statement:

for (var dir=1, i=0; i<arr.length; i+= (i+1)%chunksize == (dir==-1) ? (dir*=-1) && chunksize : dir)
    exec(i); // or whatever you need to do

This function accepts an array and a blocksize (in your example, 5)

function forwardAndBack(arr, blocksize){
  var i, j, l = arr.length ;
  for (i = 0 ; i < l ; i++){
    if (i % (2 * blocksize) > (blocksize - 1)){
      j = i + (blocksize - (2*(i % blocksize)))-1 ;
    }
    else {
      j = i ; 
    }
    arr[j] && myFunction(arr[j]) ;  // In case you've gone too high
  }
}

Used like this:

var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24] ;
var result = [] ;
function myFunction(x){result.push(x)} ;

forwardAndBack(arr, 5);

console.log(result) ;  // returns [0, 1, 2, 3, 4, 9, 8, 7, 6, 5, 10, 11, 12, 13, 14, 19, 18, 17, 16, 15, 20, 21, 22, 23, 24]
发布评论

评论列表(0)

  1. 暂无评论