2013-07-02 15 views
76
二维阵列

我有一个数组的数组,像这样:移调在JavaScript

[ 
    [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; 
} 

然而,这似乎是笨重的,我觉得应该有一个EAS更方便的方式来做到这一点。在那儿?

+3

你能保证这两个维度永远是一样的吗? 1x1,2x2,3x3等什么是'arrayLength'参数完全用于?为了确保你不超出数组中的一定数量的元素? – crush

+6

这与JQuery无关,我改了标题。 – Joe

+4

看看这个:http://stackoverflow.com/questions/4492678/to-swap-rows-with-columns-of-matrix-in-javascript-or-jquery。你在做什么是转置矩阵 – stackErr

回答

97
array[0].map((col, i) => array.map(row => row[i])); 

map要求在一个阵列的每个元素中,为了提供一个功能callback一次,并构造从结果的新数组。 callback仅对已分配值的数组索引进行调用;对于已删除或从未分配过值的索引,不会调用它。

callback被调用三个参数:元素的值,元素的索引和被遍历的Array对象。 [source]

+4

这是一个很好的解决方案。但是,如果您关心性能,则应使用OP的原始解决方案(使用缺陷修复程序来支持M×N个阵列,其中M!= N)。 [检查此jsPerf](http://jsperf.com/transpose-2d-array) –

+1

如果您在同一个阵列上使用它两次,它会返回到第一个旋转90'的intead –

+0

这没有'为我工作。但是,[this did](https://stackoverflow.com/a/13241545/3491991) – zelusp

33

你可以使用underscore.js

_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]]) 
+3

这很漂亮 - 同样,下划线对我来说比jQuery更有必要。 –

+1

可笑的优雅的解决方案,谢谢你。 – henrebotha

1
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; 
} 
10

你可以只做一个通做它在就地:

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; 
    } 
    } 
} 
+1

如果你的数组不是正方形(例如2×8),这不起作用我猜 –

+2

这个解决方案改变了原始数组。如果你仍然需要原始数组,那么这个解决方案可能不是你想要的。其他解决方案会创建一个新数组。 – Alex

3

您可以通过实现这个没有循环下列。

它看起来非常优雅,它不需要任何的依赖性如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>

+0

为什么你不想没有循环呢?没有循环它很慢 – Downgoat

+3

不.map是一个循环?只有一个你没有看到?我的意思是这是通过每一个输入,并做它的东西... – Julix

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]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

+2

令人敬畏的同时使用拉姆达和ES6来解决这个 –

+0

Ramda实际上有一个['转置'函数](http://ramdajs.com/docs /#转置)现在。 –

12

最短的方式与lodash/underscorees6

_.zip(...matrix) 

其中matrix可能是:

const matrix = [[1,2,3], [1,2,3], [1,2,3]]; 
+0

或者,没有ES6:'_.zip。应用(_,矩阵)' – ach

+7

关闭但是_.unzip(矩阵)更短;) – Vigrant

+1

你能扩充这个吗?我不明白你在说什么。那个简短的snipplet应该解决这个问题?或者它只是一个部分或什么? – Julix

28

这里是我在现代的浏览器(不依赖)的实现:

transpose = m => m[0].map((x,i) => m.map(x => x[i])) 
+0

如果您在同一个数组上使用它两次,它会返回到第一个旋转90 ' –

+9

转置矩阵的转置是原始矩阵,请参阅http://www.math.nyu.edu/~neylon/linalgfall04/project1/dj/proptranspose.htm –

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

所有有移调被映射的元素列第一,然后通过行。

1

ES6 1liners为:

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

所以同奥斯卡,但你宁愿按顺时针方向旋转:

let rotate = a => a[0].map((col, c) => a.map((row, r) => a[r][c]).reverse()) 
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; 
    } 
+2

感谢您的快速解决方案。 – Zzap

+1

真棒..伟大的作品 –

+0

虽然没有回答这个问题;移调就像...沿对角线镜像(不旋转) – DerMike

5

整洁纯:

[[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]]), 
    [] 
) 
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 
} 
2

很多好的答案在这里!我将它们整合成一个答案,并更新了一些代码的一个更现代的语法: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作者: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; 
} 

香草就地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]]; 
    } 
    } 
} 
2

如果使用RamdaJS是一个选项,这可以在实现启发一行:R.transpose(myArray)

+0

单行解决方案/建议应发表评论。 – Rumit

+0

@Rumit你从哪里得到了这个想法? – dcastro

+0

@dcastro,[作为答案发布的评论将被删除。](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-c​​an - 我做 - 而不是) – Rumit