我有一系列数组,例如:
[
[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;
}
然而,这看起来很笨重,我觉得应该有一种更简单的方法。有吗?
答案 0 :(得分:148)
array[0].map((col, i) => array.map(row => row[i]));
使用三个参数调用
map
按顺序为数组中的每个元素调用一次提供的callback
函数,并从结果中构造一个新数组。仅为已分配值的数组的索引调用callback
;对于已删除或从未分配过值的索引,不会调用它。
callback
:元素的值,元素的索引和遍历的Array对象。 [source]
答案 1 :(得分:38)
您可以使用underscore.js
_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
答案 2 :(得分:31)
这是我在现代浏览器中的实现(没有依赖):
transpose = m => m[0].map((x,i) => m.map(x => x[i]))
答案 3 :(得分:18)
lodash
/ underscore
和es6
的最短路径:
_.zip(...matrix)
matrix
可以是:
const matrix = [[1,2,3], [1,2,3], [1,2,3]];
答案 4 :(得分:11)
这里有很多好的答案!我将它们合并为一个答案并更新了一些代码以获得更现代的语法:
受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])
), []);
}
Lodash / Underscore by 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;
}
Vanilla就地ES6方法受Emanuel Saringan
的启发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]];
}
}
}
答案 5 :(得分:9)
你可以通过一次传递来就地完成:
function transpose(arr,arrLen) {
for (var i = 0; i < arrLen; i++) {
for (var j = 0; j <i; j++) {
//swap element[i,j] and element[j,i]
var temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
答案 6 :(得分:9)
干净利落:
[[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]]),
[]
)
答案 7 :(得分:6)
使用Array.map
的另一种变体。使用索引可以在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];
});
});
所有转置都是先按行映射元素,然后按行映射。
答案 8 :(得分:4)
如果您可以选择使用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]]
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
&#13;
答案 9 :(得分:4)
如果使用RamdaJS是一个选项,可以在一行中实现:R.transpose(myArray)
答案 10 :(得分:3)
编辑:此答案不会转置矩阵,而是将其旋转。我没有仔细阅读这个问题:D
顺时针和逆时针旋转:
function rotateCounterClockwise(a){
var n=a.length;
for (var i=0; i<n/2; i++) {
for (var j=i; j<n-i-1; j++) {
var tmp=a[i][j];
a[i][j]=a[j][n-i-1];
a[j][n-i-1]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a[n-j-1][i];
a[n-j-1][i]=tmp;
}
}
return a;
}
function rotateClockwise(a) {
var n=a.length;
for (var i=0; i<n/2; i++) {
for (var j=i; j<n-i-1; j++) {
var tmp=a[i][j];
a[i][j]=a[n-j-1][i];
a[n-j-1][i]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a[j][n-i-1];
a[j][n-i-1]=tmp;
}
}
return a;
}
答案 11 :(得分:2)
Spread
语法不应用作 push
的替代,它只应在您不想改变现有数组时使用。算法:
对于每一列,只需检查结果矩阵中该列是否有一行,如果已经有一行,则只需 push
元素,否则创建一个新的行数组,然后 push
。
因此,与上述许多其他解决方案不同,该解决方案不会一次又一次地创建新数组,而是推送到同一个数组上。
另外,花一些时间来了解 Nullish Coalescing Operator 的使用。
const
transpose = arr => arr.reduce((m, r) => (r.forEach((v, i) => (m[i] ??= [], m[i].push(v))), m), []),
matrix = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
console.log(transpose(matrix))
答案 12 :(得分:2)
另一种方法是从外部到内部迭代数组,并通过映射内部值来简化矩阵。
const
transpose = array => array.reduce((r, a) => a.map((v, i) => [...(r[i] || []), v]), []),
matrix = [[1, 2, 3], [1, 2, 3], [1, 2, 3]];
console.log(transpose(matrix));
答案 13 :(得分:2)
ES6 1liners as:
:after
和Óscar一样,但是你宁愿顺时针旋转它:
let invert = a => a[0].map((col, c) => a.map((row, r) => a[r][c]))
答案 14 :(得分:2)
通过使用以下内容,您可以在没有循环的情况下实现此目的。
它看起来非常优雅,并且不需要jQuery的Underscore.js等任何依赖项。
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>
答案 15 :(得分:1)
我发现上述答案难以阅读或过于冗长,所以我自己写了一个。我认为这是在线性代数中实现转置的最直观的方法,你不做值交换,而只是将每个元素插入到新矩阵中的正确位置:
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
}
答案 16 :(得分:1)
由于到目前为止还没有人提到功能递归方法,因此我认为这是。 Haskell的Data.List.transpose
的改编版。
var transpose = as => as.length ? as[0].length ? [ as.reduce( (rs,a) => a.length ? ( rs.push(a[0])
, rs
)
: rs
, []
)
, ...transpose(as.map(a => a.slice(1)))
]
: transpose(as.slice(1))
: [],
mtx = [[1], [1, 2], [1, 2, 3]];
console.log(transpose(mtx))
.as-console-wrapper {
max-height: 100% !important
}
答案 17 :(得分:0)
我认为这更具可读性。它使用Array.from
,逻辑与使用嵌套循环相同:
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);
答案 18 :(得分:0)
TypeScript中的一种无库实现,适用于不会截断数组的任何矩阵形状:
const rotate2dArray = <T>(array2d: T[][]) => {
const rotated2d: T[][] = []
return array2d.reduce((acc, array1d, index2d) => {
array1d.forEach((value, index1d) => {
if (!acc[index1d]) acc[index1d] = []
acc[index1d][index2d] = value
})
return acc
}, rotated2d)
}
答案 19 :(得分:0)
不会改变给定数组的单线。
a[0].map((col, i) => a.map(([...row]) => row[i]))
答案 20 :(得分: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]));
}
答案 21 :(得分:0)
const transpose = array => array[0].map((r, i) => array.map(c => c[i]));
console.log(transpose([[2, 3, 4], [5, 6, 7]]));
答案 22 :(得分:0)
我没有找到令我满意的答案,所以我自己写了一个书,我认为它很容易理解和实施,并且适合所有情况。
transposeArray: function (mat) {
let newMat = [];
for (let j = 0; j < mat[0].length; j++) { // j are columns
let temp = [];
for (let i = 0; i < mat.length; i++) { // i are rows
temp.push(mat[i][j]); // so temp will be the j(th) column in mat
}
newMat.push(temp); // then just push every column in newMat
}
return newMat;
}
答案 23 :(得分:0)
这不仅是一个超级高效的解决方案,而且是一个非常简短的解决方案。
算法时间复杂度:O(n log n)
const matrix = [
[1,1,1,1],
[2,2,2,2],
[3,3,3,3],
[4,4,4,4]
];
matrix.every((r, i, a) => (
r.every((_, j) => (
j = a.length-j-1,
[ r[j], a[j][i] ] = [ a[j][i], r[j] ],
i < j-1
)),
i < length-2
));
console.log(matrix);
/*
Prints:
[
[1,2,3,4],
[1,2,3,4],
[1,2,3,4],
[1,2,3,4]
]
*/
上面的例子只会进行 6 次迭代。
对于更大的矩阵,比如 100x100,它将执行 4,900 次迭代,这比此处提供的任何其他解决方案快 51%。
原理很简单,你只遍历矩阵的上对角线,因为对角线永远不会改变,下对角线是和上对角线一起切换的,所以没有理由遍历它以及。这样,您可以节省大量运行时间,尤其是在大型矩阵中。
答案 24 :(得分:0)
function invertArray(array,arrayWidth,arrayHeight) {
var newArray = [];
for (x=0;x<arrayWidth;x++) {
newArray[x] = [];
for (y=0;y<arrayHeight;y++) {
newArray[x][y] = array[y][x];
}
}
return newArray;
}