最大化while循环的效率

时间:2018-08-14 19:12:29

标签: javascript optimization while-loop

我有一个while循环,应该在2维中随机植入numberOfTruth真值。我只是要更改它们,如果它们还不为真,并且只能更改numberOfTruths次:

function truthfulArray(maxY, maxX, numberOfTruths, array) {
  var x;
  var y;
  var counter = 0;

  while (counter < numberOfTruths) {
    x = generateRandomNumber(maxX);
    y = generateRandomNumber(maxY);

    if (!array[x][y]) {
      array[x][y] = true;
      counter++;
    }
  }

  return array;
}

我可以看到与二维数组大小有关的优化问题,并且随着numberOfTruths接近maxY和maxX的乘积,它将浪费大量资源来完成任务。我想知道我可以对功能进行哪些调整以使其更有效。预先感谢!

*** generateRandomNumber(max)是一个简单的函数,它返回从0到输入的最大值的随机数。

2 个答案:

答案 0 :(得分:0)

基于@Bergi的评论,这是一种优化。它假定数组开头是空的(或者,它不在乎,只是覆盖了东西)。

当填充因子(N / (X * Y))低时(使用X = Y = 500进行测试),它会变慢,但似乎比原始实现要快40%,并且果断地快(例如3倍) 80%。 (您可能希望将其用作试探法。)

通常的想法是,我们首先从行的开头填充随机行,然后使用Fisher-Yates随机播放将每一行分散开。与原始版本相比,我已经将yx进行了转换,因为这就是我习惯于处理2D数组的方式。 :D

function shuffle(array) {  // h/t https://bost.ocks.org/mike/shuffle/
  var m = array.length, t, i;
  while (m) {
    i = Math.floor(Math.random() * m--);
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }
  return array;
}

function truthfulArrayFillRows(maxY, maxX, numberOfTruths, array) {
  var nLeft = numberOfTruths;
  var nSeededPerRow = new Array(maxY).fill(0);

  // Seed rows randomly with trues starting from the left
  while(nLeft > 0) {
    var y = generateRandomNumber(maxY);
    var x = nSeededPerRow[y];
    if(x < maxX) {
        array[y][x] = true;
        nLeft --;
        nSeededPerRow[y] ++;
    }
  }

  // Shuffle the rows we seeded
  for(var y = 0; y < maxY; y++) {
    if(nSeededPerRow[y] > 0) {
        shuffle(array[y]);
    }
  }
  return array;
}

答案 1 :(得分:0)

您可以从所有可能的职位中随机选择numberOfTruth个职位,而可以从许多有效职位中随机选择numberOfTruth个职位。为此,您必须先找到那些位置。

function shuffle(a) {
    var j, x, i;
    for (i = a.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = a[i];
        a[i] = a[j];
        a[j] = x;
    }
    return a;
}

function chunkArray(myArray, chunk_size){
    var results = [];
    while (myArray.length) {
        results.push(myArray.splice(0, chunk_size));
    }    
    return results;
}

function flatten(array) {
  var flattened=[];
  for (var i=0; i<array.length; ++i) {
      var current = array[i];
      for (var j=0; j<current.length; ++j)
          flattened.push(current[j]);
  }
  return flattened;
}

function truthfulArray(maxY, maxX, numberOfTruths, array){
  var flatArray = flatten(array);
  var validPositions = flatArray.map(function(e, i){if(!e) return i});
  var randomPositions = shuffle(validPositions).slice(0, numberOfTruths);

  randomPositions.forEach(function(i){flatArray[i] = true;});

  return chunkArray(flatArray, maxY);
}


var maxX = 20, maxY = 30;
var array = Array(maxX).fill(Array(maxY).fill(false));
truthfulArray(maxY, maxX, 40, array);

这种方法是否更有效取决于您的数据。如果有很多有效的职位可供选择,那么您的代码应该完全有效。数组中的true越多,您的代码(随机)命中它们的可能性就越小。在这种情况下,我描述的方法将更加有效。 希望对您有所帮助。