在 JavaScript 中按对角键重新排列/转置数组项

Rearrange / transpose array items by keys diagonally in JavaScript

我有一个 字符串数组 ,例如:

var arr=["dog", "cat", "bear", "wolf", "lynx", "hare", "sheep", "owl", "hen"];

要引用这些值中的任何一个,都有从0到8的对应键,即arr[3]对应于“wolf”。实际数组的项目数量可能会有所不同,并且其中有超过 100 个项目。在这个例子中有 9 [0,1,2,3,4,5,6,7,8].

我想要完成的是按对角键重新排列项目,即从:

[0,1,2,
 3,4,5,
 6,7,8]

进入:

[0,2,5,
 1,4,7,
 3,6,8]

即进入[0,2,5,1,4,7,3,6,8],因此也从原来的相应值的序列:

var arr=["dog", "cat", "bear", "wolf", "lynx", "hare", "sheep", "owl", "hen"];

导致重新排列的值:

var arr2=["dog", "bear", "hare", "cat", "lynx", "wolf", "owl", "sheep", "hen"];

这个解决方案的使用将在更复杂的字符串项目可视化中实现(每个字符串都由对应于另一个数据的 UTF-8 编码值的二进制数字组成)呈方形,特别是从左侧对角线排列顶角。提前致谢!

  1. path 方法,给出给定 [row, col]
  2. 的有效对角线路径
  3. diagonals,从第一列和最后一行开始的聚合路径。
  4. 根据生成的对角线路径简单map洗牌。

PS: 未测试数组长度不是正方形的情况。

const path = (row, col, len, res) => {
  while (row > -1 && col < len) {
    res.push([row, col]);
    row--;
    col++;
  }
  return res;
};

const diagonals = (len) => {
  const res = [];
  for (let i = 0; i < len; i++) {
    path(i, 0, len, res);
  }
  for (let j = 1; j < len; j++) {
    path(len - 1, j, len, res);
  }
  return res;
};

// const input = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const input = ["dog", "cat", "bear", "wolf", "lynx", "hare", "sheep", "owl", "hen"]
const len = Math.floor(Math.sqrt(input.length));

const output = [...input]
diagonals(len).map(([row, col], i) => output[row * len + col] = input[i]);

console.log(output.join(', '));

我花了一些时间来正确地计算数学,但我能够创建一个函数,其中 returns 一个索引数组以正确的顺序排列:

function getDiagonalArrayIndexes(length) {
  const sqrt = Math.floor(Math.sqrt(length));
  
  const formula = (x, y) => (y + x) * (y + x + 1) / 2 + x;
  
  return Array.from({ length: sqrt*sqrt }, (_, i) => {
    let x = i % sqrt, y = Math.floor(i / sqrt);
    
    if (x + y < sqrt) {
      return formula(x, y);
    } else {
      return length - 1  - formula(sqrt - 1  - x, sqrt - 1  - y);
    }
  })
  // In case length's square root is not an integer
  .concat(new Array(length - sqrt * sqrt).fill(null));
}

printSquare( getDiagonalArrayIndexes(9) );
printSquare( getDiagonalArrayIndexes(16) );
printSquare( getDiagonalArrayIndexes(25) );                                                                                       /* Just for the demo */ function printSquare(n){const o=Math.sqrt(n.length),t=[];for(var e=0,a=0;e<n.length;e++)e>=o&&e%o==0&&a++,t[a]=t[a]||[],t[a].push(n[e]);console.log("[\n"+t.map(n=>n.map(n=>("  "+n).slice(-3)).join(",")).join(",\n")+"\n]")}document.body.innerHTML="<style>\n  .as-console-wrapper { max-height: 100% !important; top: 0; }\n</style>";

然后您可以重复使用它并使用您的数据映射索引:

function reorderDiagonally(arr) {
  return getDiagonalArrayIndexes(arr.length)
         .map(i => i !== null ? arr[i] : '');
}

var arr = ["dog", "cat", "bear", "wolf", "lynx", "hare", "sheep", "owl", "hen"];

console.log(JSON.stringify( reorderDiagonally(arr) ));                                                                                                                   /* Just for the demo */ function getDiagonalArrayIndexes(r){const t=Math.floor(Math.sqrt(r)),n=(r,t)=>(t+r)*(t+r+1)/2+r,l=Array.from({length:t*t},(l,a)=>{let e=a%t,o=Math.floor(a/t);return e+o<t?n(e,o):r-1-n(t-1-e,t-1-o)});return l.concat(new Array(r-l.length).fill(null))}