JavaScriptで2次元配列の転置を行う

I've got a array of arrays, like:

[
    [1,2,3],
    [1,2,3],
    [1,2,3],
]

これを転置して、以下のような配列を得たい。

[
    [1,1,1],
    [2,2,2],
    [3,3,3],
]

ループを使ってプログラム的に行うことは難しくありません。

function transposeArray(array, arrayLength){
    var newArray = [];
    for(var i = 0; i < array.length; i++){
        newArray.push([]);
    };

    for(var i = 0; i < array.length; i++){
        for(var j = 0; j < arrayLength; j++){
            newArray[j].push(array[i][j]);
        };
    };

    return newArray;
}

しかし、これはかさばるので、もっと簡単な方法があるような気がしています。あるのでしょうか?

質問へのコメント (5)
ソリューション
array[0].map((col, i) => array.map(row => row[i]));

mapは、配列の各要素に対して、指定された callback 関数を順に 1 回ずつ呼び出し、その結果から新しい配列を作成します。コールバック関数は、値が割り当てられている配列のインデックスに対してのみ呼び出され、削除されたインデックスや一度も値が割り当てられていないインデックスに対しては呼び出されません。

要素の値、要素のインデックス、走査されるArrayオブジェクトの3つの引数で呼び出されます。

解説 (8)

underscore.js]1を使えばいいんです。

_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
解説 (5)

これが最新のブラウザでの実装です(依存関係なし)。

transpose = m => m[0].map((x,i) => m.map(x => x[i]))
解説 (2)

lodash / underscorees6の最短の方法:

_.zip(...matrix)

ここで、「マトリックス」は次のようになります。

const matrix = [[1,2,3], [1,2,3], [1,2,3]];
解説 (5)

ここに多くの良い答えがあります。! それらを1つの回答に統合し、より最新の構文のためにコードのいくつかを更新しました。

Fawad GhafoorおよびÓ scar Gó mez Alcañ izに触発されたワンライナー。

function transpose(matrix) {
  return matrix[0].map((col, i) => matrix.map(row => row[i]));
}

function transpose(matrix) {
  return matrix[0].map((col, c) => matrix.map((row, r) => matrix[r][c]));
}

Andrew Tatomyrによる縮小機能アプローチスタイル。

function transpose(matrix) {
  return matrix.reduce((prev, next) => next.map((item, i) =>
    (prev[i] || []).concat(next[i])
  ), []);
}

[marcel]によるLodash / Underscore(https://stackoverflow.com/users/4796214/marcel)

function tranpose(matrix) {
  return _.zip(...matrix);
}

// Without spread operator.
function transpose(matrix) {
  return _.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
}

バニラアプローチ

function transpose(matrix) {
  const rows = matrix.length, cols = matrix[0].length;
  const grid = [];
  for (let j = 0; j < cols; j++) {
    grid[j] = Array(rows);
  }
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      grid[j][i] = matrix[i][j];
    }
  }
  return grid;
}

Emanuel Saringanに触発されたバニラのインプレースES6アプローチ。

function transpose(matrix) {
  for (var i = 0; i < matrix.length; i++) {
    for (var j = 0; j < i; j++) {
      const temp = matrix[i][j];
      matrix[i][j] = matrix[j][i];
      matrix[j][i] = temp;
    }
  }
}

// Using destructing
function transpose(matrix) {
  for (var i = 0; i < matrix.length; i++) {
    for (var j = 0; j < i; j++) {
      [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
    }
  }
}
解説 (0)

きちんとした純粋な:

[[0, 1], [2, 3], [4, 5]].reduce((prev, next) => next.map((item, i) =>
    (prev[i] || []).concat(next[i])
), []); // [[0, 2, 4], [1, 3, 5]]

空の配列が提供されている場合、以前のソリューションは失敗につながる可能性があります。

ここに関数としてあります:

function transpose(array) {
    return array.reduce((prev, next) => next.map((item, i) =>
        (prev[i] || []).concat(next[i])
    ), []);
}

console.log(transpose([[0, 1], [2, 3], [4, 5]]));

更新。。 スプレッド演算子を使用すると、さらにうまく記述できます。

const transpose = matrix => matrix.reduce(($, row) =>
    row.map((_, i) => [...($[i] || []), row[i]]), 
    []
)
解説 (0)

1つのパスのみを実行することで、インプレースでそれを行うことができます。


function transpose(arr,arrLen) {
  for (var i = 0; i < arrLen; i++) {
    for (var j = 0; j 
解説 (2)

Array.ma pを使用した別のバリエーション。 インデックスを使用すると、行列を Mで転置できます。 != N:

// Get just the first row to iterate columns first
var t = matrix[0].map(function (col, c) {
    // For each column, iterate all rows
    return matrix.map(function (row, r) { 
        return matrix[r][c]; 
    }); 
});

転置に必要なのは、要素を列ごとにマッピングし、次に行ごとにマッピングすることだけです。

解説 (0)

Ramda JSおよびES6構文を使用するオプションがある場合は、それを行う別の方法を次に示します。

const transpose = a => R.map(c => R.map(r => r[c], a), R.keys(a[0]));

console.log(transpose([
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12]
])); // =>  [[1,5,9],[2,6,10],[3,7,11],[4,8,12]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

解説 (2)

アレイを外側から内側に反復して別のアプローチを行い、内部値をマッピングしてマトリックスを減らします。

。 。 const。 transpose = array => array.re duce((r、a)=> a.ma p((v、i)=> [。..(r [i] || [])、v])、[])、。 行列= [[1、2、3]、[1、2、3]、[1、2、3]];。

console.log(transpose(matrix));

解説 (1)

RamdaJSの使用がオプションである場合、これは1行で達成できます: R.tr anspose(myArray)

解説 (0)

編集:この答えはマトリックスを転置するのではなく、回転させます。 そもそも質問を注意深く読んでいませんでした:D

時計回りおよび反時計回りの回転:


    function rotateCounterClockwise(a){
        var n=a.length;
        for (var i=0; i
解説 (4)

ループなしでこれを達成するには、以下を使用します。

それは非常にエレガントに見え、Underscore.jsjQueryなどの依存関係を必要としません。

function transpose(matrix) {  
    return zeroFill(getMatrixWidth(matrix)).map(function(r, i) {
        return zeroFill(matrix.length).map(function(c, j) {
            return matrix[j][i];
        });
    });
}

function getMatrixWidth(matrix) {
    return matrix.reduce(function (result, row) {
        return Math.max(result, row.length);
    }, 0);
}

function zeroFill(n) {
    return new Array(n+1).join('0').split('').map(Number);
}

最小化。

function transpose(m){return zeroFill(m.reduce(function(m,r){return Math.max(m,r.length)},0)).map(function(r,i){return zeroFill(m.length).map(function(c,j){return m[j][i]})})}function zeroFill(n){return new Array(n+1).join("0").split("").map(Number)}

---。

これは私が一緒に投げたデモです。 ループの不足に注意してください:-)。

// Create a 5 row, by 9 column matrix.
var m = CoordinateMatrix(5, 9);

// Make the matrix an irregular shape.
m[2] = m[2].slice(0, 5);
m[4].pop();

// Transpose and print the matrix.
println(formatMatrix(transpose(m)));

function Matrix(rows, cols, defaultVal) {
    return AbstractMatrix(rows, cols, function(r, i) {
        return arrayFill(cols, defaultVal);
    });
}
function ZeroMatrix(rows, cols) {
    return AbstractMatrix(rows, cols, function(r, i) {
        return zeroFill(cols);
    });
}
function CoordinateMatrix(rows, cols) {
    return AbstractMatrix(rows, cols, function(r, i) {
        return zeroFill(cols).map(function(c, j) {
            return [i, j];
        });
    });
}
function AbstractMatrix(rows, cols, rowFn) {
    return zeroFill(rows).map(function(r, i) {
        return rowFn(r, i);
    });
}
/** Matrix functions. */
function formatMatrix(matrix) {
    return matrix.reduce(function (result, row) {
        return result + row.join('\t') + '\n';
    }, '');
}
function copy(matrix) {  
    return zeroFill(matrix.length).map(function(r, i) {
        return zeroFill(getMatrixWidth(matrix)).map(function(c, j) {
            return matrix[i][j];
        });
    });
}
function transpose(matrix) {  
    return zeroFill(getMatrixWidth(matrix)).map(function(r, i) {
        return zeroFill(matrix.length).map(function(c, j) {
            return matrix[j][i];
        });
    });
}
function getMatrixWidth(matrix) {
    return matrix.reduce(function (result, row) {
        return Math.max(result, row.length);
    }, 0);
}
/** Array fill functions. */
function zeroFill(n) {
  return new Array(n+1).join('0').split('').map(Number);
}
function arrayFill(n, defaultValue) {
    return zeroFill(n).map(function(value) {
        return defaultValue || value;
    });
}
/** Print functions. */
function print(str) {
    str = Array.isArray(str) ? str.join(' ') : str;
    return document.getElementById('out').innerHTML += str || '';
}
function println(str) {
    print.call(null, [].slice.call(arguments, 0).concat(['<br />']));
}
#out {
    white-space: pre;
}
<div id="out"></div>

解説 (2)

ES6 1ライナー:

let invert = a => a[0].map((col, c) => a.map((row, r) => a[r][c]))

Ó scar'sと同じですが、時計回りに回転させます。

let rotate = a => a[0].map((col, c) => a.map((row, r) => a[r][c]).reverse())
解説 (0)

上記の答えは読みにくいか、冗長すぎるため、自分で書きます。 これは線形代数で転置を実装する最も直感的な方法だと思います。値交換を実行するのではなく、各要素を新しい行列の適切な場所に挿入するだけです。

function transpose(matrix) {
  const rows = matrix.length
  const cols = matrix[0].length

  let grid = []
  for (let col = 0; col < cols; col++) {
    grid[col] = []
  }
  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      grid[col][row] = matrix[row][col]
    }
  }
  return grid
}
解説 (0)

これはもう少し読みやすいと思います。 Array.fr omを使用し、ロジックはネストされたループの使用と同じです。

var arr = [
  [1, 2, 3, 4],
  [1, 2, 3, 4],
  [1, 2, 3, 4]
];

/*
 * arr[0].length = 4 = number of result rows
 * arr.length = 3 = number of result cols
 */

var result = Array.from({ length: arr[0].length }, function(x, row) {
  return Array.from({ length: arr.length }, function(x, col) {
    return arr[col][row];
  });
});

console.log(result);

長さが不等な配列を扱っている場合は、「arr [0]。length」を別のものに置き換える必要があります。

var arr = [
  [1, 2],
  [1, 2, 3],
  [1, 2, 3, 4]
];

/*
 * arr[0].length = 4 = number of result rows
 * arr.length = 3 = number of result cols
 */

var result = Array.from({ length: arr.reduce(function(max, item) { return item.length > max ? item.length : max; }, 0) }, function(x, row) {
  return Array.from({ length: arr.length }, function(x, col) {
    return arr[col][row];
  });
});

console.log(result);

解説 (0)

function invertArray(array,arrayWidth,arrayHeight) {
  var newArray = [];
  for (x=0;x
解説 (0)

配列を切り捨てないマトリックス形状で動作するTypeScriptのライブラリフリーの実装:


const rotate2dArray =< T>(array2d:T [] [])=> {。
    const rotated2d:T [] [] = []。

    array2d.re duce((acc、array1d、index2d)=>を返します。 {。
        array1d.fo rEach((値、index1d)=> {。
            if(。!acc [index1d])acc [index1d] = []。

            acc [index1d] [index2d] =値。
        })。

        accを返します。
    }、回転2d)。
}。
``。
解説 (0)

指定された配列を変更しないワンライナー。


a [0] .map((col、i)=> a.ma p(([。..row])=> row [i]))。
``。
解説 (0)
reverseValues(values) {
        let maxLength = values.reduce((acc, val) => Math.max(val.length, acc), 0);
        return [...Array(maxLength)].map((val, index) => values.map((v) => v[index]));
}
解説 (1)