Rearrange / transpose array items by keys diagonally in JavaScript

I have an array of strings, for example:

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

To refer to any of these values, there are corresponding keys from 0 to 8, i.e. the arr[3] corresponds to “wolf”. The amount of items of the actual array may vary and have more than 100 items in it. In this example there are 9 [0,1,2,3,4,5,6,7,8].

What I would like to accomplish is to rearrange the items by their keys diagonally, i.e. from:

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

into:

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

i.e. into [0,2,5,1,4,7,3,6,8], and thus also the sequence of the corresponding values from the original:

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

resulting into the rearranged values:

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

The use of this solution would be implemented in more complex visualization of string items (strings each consisting of binary digits that correspond to UTF-8 encoded values of another data) in square shape, arranging them diagonally specifically from the left top corner. Thank you in advance!

Answer

It took some time for me to get the math right, but I was able to make a function which returns an Array of indexes in the correct order:

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>";

You can then reuse it and map the indexes using your data:

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