在对角线中查找数组中的相同值

时间:2016-10-21 23:16:05

标签: javascript arrays

我有一个数组,让我们说

var array = [ [1, 0, 0, 0, 0, 0, 0],
              [0, 1, 0, 0, 0, 1, 0],
              [0, 0, 1, 0, 1, 0, 0],
              [0, 0, 0, 1, 0, 0, 0],
              [0, 0, 1, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 0, 0]
            ]

我想创建一个找到任何匹配的数字,其中一个数字在对角线上出现四次。

目前我正在使用

function checkDiagonal(array, bottomToTop) {
    var Ylength = array.length;
    var Xlength = array[0].length;
    var maxLength = Math.max(Xlength, Ylength);
    var temp;
    var returnArray = [];
    for (var k = 0; k <= 2 * (maxLength - 1); ++k) {
        temp = [];
        for (var y = Ylength - 1; y >= 0; --y) {
            var x = k - (bottomToTop ? Ylength - y : y);
            if (x >= 0 && x < Xlength) {
                temp.push(array[y][x]);
            }
        }
        if(temp.length > 0) {
            returnArray.push(temp.join(''));
        }
    }
    return returnArray;
}

然而,并不总能找到所有解决方案

3 个答案:

答案 0 :(得分:2)

有趣的案例。实际上很难找到/写一个简单的方法。 我试图了解你的脚本,但发现它有点难以跟踪/调试,所以试图重现你在我自己的脚本中所做的并设法获得所需的结果。它比你的代码行更多,但它有一些变量与一些注释一起声明,所以它更容易理解(对于其他人,将来)。

希望这会有所帮助:

function checkDiagonal(array, matchCount) {
  var result = [];

  if(array.length >= matchCount) {
    // Search towards bottom-right.
    result = result.concat(getDiagonalResult(array, matchCount, 1));

    // Search towards top-right.
    result = result.concat(getDiagonalResult(array, matchCount, -1));
  } else {
    // No use searching if not enough rows are present.
  }

  return result;
}

function getDiagonalResult(array, matchCount, direction) {
  var result = [];

  // Specific from and to points to only search in possible rows (e.g. no use searching top-right on first row).
  var yFrom, yTo;

  // Search direction (bottom-right vs top-right).
  switch(direction) {
      // Bottom-right.
    case 1:
      yFrom = 0;
      yTo = (array.length - matchCount);
      break;

      // Top-right.
    case -1:
      yFrom = (matchCount - 1);
      yTo = (array.length - 1);
      break;
  }

  // Loop through all 'rows'.
  for(var y = yFrom; y <= yTo; y++) {

    // Loop through all 'columns'.
    for(var x = 0; x <= (array[y].length - matchCount); x++) {

      // Current value to match on.
      var originalValue = array[y][x];
      var matches = [];

      // Get matches.
      for(var i = 0; i < matchCount; i++) {
        // Search direction (row up or down).
        var yDirection = (i * direction);

        var value = array[y+yDirection][x+i];

        if(value === originalValue) {
          matches.push(value);
        }
      }

      if(matches.length == matchCount) {
        result.push(matches.join(""));
      }
    }

  }

  return result;
}

var array = [
  [1, 0, 0, 0, 0, 0, 0],
  [0, 1, 0, 0, 0, 1, 0],
  [0, 0, 1, 0, 1, 0, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0]
];

console.log(checkDiagonal(array, 4));

答案 1 :(得分:0)

我会通过旋转每个子阵列来预处理数组,以便形成对角线的数字相互排列。首先定义函数以在任一方向上通过n元素旋转单个数组:

const rotateLeft     = (array, n) => array.slice(n).concat(array.slice(0, n));
const rotateRight    = (array, n) => rotateLeft(array, -n);

并且可以通过在任一方向上不断增加的数量来旋转每个子阵列:

const rotateAllLeft  = array => array.map(rotateLeft);
const rotateAllRight = array => array.map(rotateRight);

你的阵列现在看起来像这样,垂直排列的那些:

var array = [ [1, 0, 0, 0, 0, 0, 0],
              [1, 0, 0, 0, 1, 0, 0],
              [1, 0, 1, 0, 0, 0, 0],
              [1, 0, 0, 0, 0, 0, 0],
              [0, 0, 0, 0, 0, 1, 0],
              [0, 0, 0, 0, 0, 0, 0]
            ]

问题现在减少到寻找垂直线。要做到这一点,首先转置数组是最容易的,你可以这样做:

const transpose = array => array[0].map((_, i) => array.map(row => row[i]));

我们现在将编写一个小函数,它接受一个数组并返回另一个数组,其值为&#34;运行&#34;具有特定价值:

const run = (array, val, cnt = 0) => array.map(elt => cnt = elt === val ? ++cnt : 0;

对于[1, 1, 1, 1, 0, 0],这将返回[1, 2, 3, 4, 0, 0]4表示到此为止的四个1值。

编写小函数来测试单个数组中某个最小长度的特定值的运行,或者在任何子数组中运行某个最小长度的特定值:

const hasRunOf = (array, val, n) => run(array, val).some(len => len >= n);
const hasAnyRunOf = (array, val, n) => array.some(subarray => hasRunOf(subarray, val, n));

现在,您可以使用

测试是否存在任何四个或更多个游戏
hasAnyRunOf(transpose(rotateAllLeft(array)), 1, 4) || 
  hasAnyRunOf(transpose(rotateAllRight(array)), 1, 4)        

捕获关于对角线运行的确切位置的信息留作练习。

答案 2 :(得分:0)

这是最好的,因为它来自我。它仅在n大小的组中计算每个元素一次。换句话说,组中存在的元素不能存在于另一个元素中。

这是一个游戏,使用最佳数量的xy起始索引,然后计算从对角线向前和向后居住的起点开始的每个元素的索引。显然,我们应该在正确的xy索引处开始和停止,我们可以在对角线上找到n个元素。这将减少n增长后要完成的工作量。因此,每组12个元素的100x100阵列的计算速度要快于每组4个元素的数组。

function getDiagonals(a,rep){
  var xLen = a[0].length,         // x dimension
      yLen = a.length,            // y dimension
      xMin = rep-1,               // minimum x value to start testing from
      xMax = xLen-rep,            // maximum x value to test up until
      yMin = rep-1,               // minimum y value to start testing from
      yMax = yLen-rep,            // maximum y value to test up until
    minDim = Math.min(yLen,xLen), // the smallest dimensison
   quadros = [],                  // the resutls array
     temp1 = [],                  // utility array #1
     temp2 = [],                  // utility array #2
     item1,                       // current element on the slash test
     item2;                       // current element on the backslash test

  for (var x = xMin; x < xLen; x++){
  	for(var y = 0; y <= x && y < minDim; y++){
  	  item1 = a[y][x-y];          // slash test on x axis
  	  item2 = a[yLen-1-y][x-y];   // backslash test on x axis
  	  temp1[0] === item1 ? temp1.length < rep-1 ? temp1.push(item1)
  	                                            : (temp1.push(item1), quadros.push(temp1), temp1 = [])
  	                     : temp1 = [item1];
  	  temp2[0] === item2 ? temp2.length < rep-1 ? temp2.push(item2)
  	                                            : (temp2.push(item2), quadros.push(temp2), temp2 = [])
  	                     : temp2 = [item2];
  	}
  	temp1 = [];
  	temp2 = [];
  }
  for (var y = 1; y <= yMax; y++){
  	for(var x = xLen-1; x >= xLen - minDim + y; x--){
  	  item1 = a[y-x+xLen-1][x];   // slash test on y axis
  	  item2 = a[yLen-y-xLen+x][x];// backslash test on y axis
  	  temp1[0] === item1 ? temp1.length < rep-1 ? temp1.push(item1)
  	                                            : (temp1.push(item1), quadros.push(temp1), temp1 = [])
  	                     : temp1 = [item1];
  	  temp2[0] === item2 ? temp2.length < rep-1 ? temp2.push(item2)
  	                                            : (temp2.push(item2), quadros.push(temp2), temp2 = [])
  	                     : temp2 = [item2];
  	}
  	temp1 = [];
  	temp2 = [];
  }
  return quadros;
}

var arr = [ [1, 0, 0, 0, 0, 0, 0],
            [0, 1, 0, 0, 0, 1, 0],
            [0, 0, 1, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0]
          ],
    brr = Array(100).fill().map(_ => Array(100).fill().map(e => ~~(Math.random()*2))),
 result = getDiagonals(arr,4);
console.log(JSON.stringify(result),result.length);
 result = getDiagonals(brr,12);
console.log(JSON.stringify(result),result.length);