J'ai un tableau de tableaux, quelque chose comme:
[
[1,2,3],
[1,2,3],
[1,2,3],
]
Je voudrais le transposer pour obtenir le tableau suivant:
[
[1,1,1],
[2,2,2],
[3,3,3],
]
Ce n'est pas difficile de le faire par programme en utilisant des boucles:
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;
}
Cela semble toutefois encombrant et j'estime qu'il devrait exister un moyen plus simple de le faire. Y a-t-il?
array[0].map((col, i) => array.map(row => row[i]));
map
appelle une fonctioncallback
fournie une fois pour chaque élément d'un tableau, dans l'ordre, et construit un nouveau tableau à partir des résultats.callback
n'est appelé que pour les index du tableau auxquels des valeurs ont été assignées; il n'est pas appelé pour les index qui ont été supprimés ou auxquels aucune valeur n'a été attribuée.
callback
est invoqué avec trois arguments: la valeur de l'élément, l'index de l'élément et l'objet Array en cours de parcours. [source]
Vous pouvez utiliser nderscore.js
_.Zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
voici mon implémentation dans un navigateur moderne (sans dépendance):
transpose = m => m[0].map((x,i) => m.map(x => x[i]))
chemin le plus court avec lodash
/underscore
et es6
:
_.Zip(...matrix)
où matrix
pourrait être:
const matrix = [[1,2,3], [1,2,3], [1,2,3]];
Beaucoup de bonnes réponses ici! Je les ai consolidées en une seule réponse et mis à jour une partie du code pour une syntaxe plus moderne:
Les one-liners inspirés par Fawad Ghafoor et Ó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]));
}
Style d'approche fonctionnelle avec réduction de 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]])
}
Approche vanille
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;
}
Approche ES6 sur place à la vanille inspirée de 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]];
}
}
}
Propre et pur:
[[0, 1], [2, 3], [4, 5]].reduce((prev, next) => next.map((item, i) =>
(prev[i] || []).concat(next[i])
), []); // [[0, 2, 4], [1, 3, 5]]
Les solutions précédentes peuvent conduire à un échec dans le cas où un tableau vide est fourni.
Ici c'est comme une fonction:
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]]));
Mise à jour. Cela peut être écrit encore mieux avec l'opérateur de propagation:
const transpose = matrix => matrix.reduce(($, row) =>
row.map((_, i) => [...($[i] || []), row[i]]),
[]
)
Vous pouvez le faire sur place en effectuant un seul passage:
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;
}
}
}
Juste une autre variante utilisant Array.map
. L’utilisation d’index permet de transposer des matrices où 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];
});
});
Tout ce qu'il y a à transposer, c'est de mapper les éléments en commençant par les colonnes, puis par ligne.
Si RamdaJS est une option, vous pouvez le faire en une seule ligne: R.transpose(myArray)
Si vous avez la possibilité d'utiliser la syntaxe Ramda JS et ES6, voici une autre façon de procéder:
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>
Une autre approche consiste à itérer le tableau de l'extérieur vers l'intérieur et à réduire la matrice en mappant les valeurs internes.
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));
Edit: Cette réponse ne transposerait pas la matrice, mais la ferait pivoter. Je n'ai pas lu la question attentivement en premier lieu: D
rotation horaire et antihoraire:
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;
}
ES6 1liners comme:
let invert = a => a[0].map((col, c) => a.map((row, r) => a[r][c]))
identique à celui d'Óscar, mais comme vous préférez le tourner dans le sens des aiguilles d'une montre:
let rotate = a => a[0].map((col, c) => a.map((row, r) => a[r][c]).reverse())
Vous pouvez y parvenir sans boucles en utilisant ce qui suit.
Il a l’air très élégant et ne nécessite aucune dépendance telle que jQuery sur nderscore.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);
}
Minified
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)}
Voici une démo que j'ai jeté ensemble. Notez le manque de boucles :-)
// 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>
Je pense que cela est légèrement plus lisible. Il utilise Array.from
et la logique est identique à l’utilisation de boucles imbriquées:
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);
Si vous avez affaire à des tableaux de longueur inégale, vous devez remplacer arr[0].length
avec quelque chose d'autre:
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);
J'ai trouvé les réponses ci-dessus difficiles à lire ou trop verbeuses, alors j'en écris une moi-même. Et je pense que c'est la manière la plus intuitive d'implémenter transposer en algèbre linéaire, vous ne faites pas échange de valeur, mais insérez simplement chaque élément au bon endroit dans la nouvelle matrice:
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
}
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;
}
Une implémentation sans bibliothèque dans TypeScript qui fonctionne pour toute forme de matrice qui ne tronque pas vos tableaux:
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)
}