जावास्क्रिप्ट में 2 डी-सरणी का स्थानांतरण


154

मुझे एक सारणी मिली है, कुछ इस प्रकार है:

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

यह, हालांकि, भारी लगता है, और मुझे लगता है कि ऐसा करने का एक आसान तरीका होना चाहिए। है?


4
क्या आप गारंटी दे सकते हैं कि दो आयाम हमेशा एक जैसे रहेंगे? 1x1, 2x2, 3x3, आदि क्या arrayLengthपैरामीटर वास्तव में उपयोग किया जाता है? यह सुनिश्चित करने के लिए कि आप सरणी में तत्वों की एक निश्चित संख्या से आगे नहीं जाते हैं?
क्रश करें

8
इसका JQuery से कोई लेना-देना नहीं है, मैंने शीर्षक बदल दिया है।
जो

4
इसे देखें: stackoverflow.com/questions/4492678/… । आप जो कर रहे हैं वह एक मैट्रिक्स ट्रांसपोज़िंग है
स्टैकएर्र

1
हां, ट्रांसपोज़िंग। इन्वर्ट करना पूरी तरह से अलग होगा और मुझे इसमें कोई दिलचस्पी नहीं है। अभी के लिए।
सोरश

3
दाहिने विकर्ण के ऊपर बाईं ओर अपरिवर्तित है, इसलिए एक अनुकूलन अवसर है।
एस मीडेन

जवाबों:


205
array[0].map((_, colIndex) => array.map(row => row[colIndex]));

mapकिसी callbackतत्व में दिए गए फंक्शन के लिए एक बार एक एरे में कॉल करते हैं , और परिणाम से एक नए एरे का निर्माण करते हैं। callbackकेवल उसी सरणी के अनुक्रमित के लिए लागू किया जाता है जिसने मान निर्दिष्ट किए हैं; यह उन अनुक्रमणिकाओं के लिए लागू नहीं किया गया है जिन्हें हटा दिया गया है या जिन्हें कभी मान निर्दिष्ट नहीं किए गए हैं।

callbackतीन तर्कों के साथ आह्वान किया गया है: तत्व का मूल्य, तत्व का सूचकांक, और ऐरे ऑब्जेक्ट का पता लगाया जा रहा है। [स्रोत]


8
यह एक अच्छा उपाय है। हालांकि, यदि आप प्रदर्शन के बारे में परवाह करते हैं, तो आपको ओपी के मूल समाधान (डब्ल्यू / बग फिक्स को एम एक्स एन सरणियों का समर्थन करने के लिए उपयोग करना चाहिए जहां एम! = 1)। इस jsPerf की जाँच करें
बिली मैककी

3
यदि आप इसे एक ही सरणी पर दो बार उपयोग करते हैं, तो यह 90 को फिर से घुमाने के पहले एक अंत में वापस आता है
ओलिवियर पोंस

3
array[0].mapइसके बजाय क्यों array.map?
जॉन वांडिवियर

4
array[0].mapक्योंकि वह कई बार पुनरावृति करना चाहता है कि कॉलम हैं, array.mapफिर भी टाइप करेंगे कि कितनी पंक्तियाँ हैं।
जोएकोज़ा

2
@BillyMcKee वर्ष 2019 में और Chrome 75 loopsकी तुलना में 45% धीमा है map। और हाँ, यह सही ढंग से स्थानांतरित करता है, इसलिए दूसरा रन प्रारंभिक मैट्रिक्स देता है।
Ebuall

41

यहाँ आधुनिक ब्राउज़र (बिना निर्भरता) में मेरा कार्यान्वयन है:

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

यदि आप इसे एक ही सरणी पर दो बार उपयोग करते हैं, तो यह 90 को फिर से घुमाने के पहले एक अंत में वापस आता है
ओलिवियर पोंस


39

आप अंडरस्कोर का उपयोग कर सकते हैं। जेएस

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

3
यह सुंदर था - इसके अलावा, अंडरस्कोर मेरे लिए jQuery की तुलना में अधिक आवश्यक है।
जॉन स्ट्रिकलर

या यदि आप एक कार्यात्मक पुस्तकालय का उपयोग कर रहे हैं जैसे rambdaआप बस कर सकते हैंconst transpose = apply(zip)
लड़का कौन जानता है स्टफ

1
यह विकल्प चयनित उत्तर से बेहतर क्यों होगा?
एलेक्स लेनेल

यह प्रश्न वर्षों पुराना है और मुझे यकीन नहीं है कि यह अब है। यह, हालांकि, स्वीकृत उत्तर के मूल संस्करण की तुलना में क्लीनर है । आप देखेंगे कि यह काफी हद तक संपादित किया गया है। ऐसा लगता है कि यह ES6 का उपयोग करता है, जो मुझे नहीं लगता कि 2013 में उपलब्ध था जब व्यापक रूप से प्रश्न पूछा गया था।
जो

25

lodash/ underscoreऔर es6: के साथ सबसे छोटा रास्ता

_.zip(...matrix)

कहाँ matrixहो सकता है:

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

या, ES6 के बिना:_.zip.apply(_, matrix)
ACH

9
बंद लेकिन _.unzip (मैट्रिक्स) कम है;)
Vigrant

1
क्या आपके द्वारा इसे विस्तार दिया जा सकता है? मुझे वह नहीं मिला जो आप यहाँ कह रहे हैं। इस समस्या को हल करने के लिए माना जाता है? या यह सिर्फ एक हिस्सा है या क्या है?
जुलिक्स

1
मेरा गश एक छोटा उपाय है। बस के बारे में सीखा ... ऑपरेटर - यह पत्र की एक सरणी में एक स्ट्रिंग को तोड़ने के लिए इस्तेमाल किया ... उत्तर के लिए धन्यवाद
जुलिक्स

22

यहाँ कई अच्छे जवाब! मैंने उन्हें एक उत्तर में समेकित किया और एक अधिक आधुनिक वाक्य रचना के लिए कुछ कोड अपडेट किए:

वन-लाइनर्स फवाद गफूर और ó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]));
}

एंड्रयू टाटोमायर द्वारा कम के साथ कार्यात्मक दृष्टिकोण शैली

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

लॉडश / अंडरस्कोर मार्सेल द्वारा

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 दृष्टिकोण इमानुएल सरिंगन से प्रेरित है

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

11

शुद्ध और शुद्ध:

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

2
मुझे नहीं पता कि मैं उस अपडेट को बेहतर कहूंगा। यह चतुर है, निश्चित है, लेकिन यह पढ़ने के लिए एक बुरा सपना है।
मेरी

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

1
यदि आपका सरणी एक वर्ग नहीं है (उदाहरण के लिए 2x8) तो यह मुझे नहीं लगता है कि काम करता है
ओलिवियर पोंस

2
यह समाधान मूल सरणी को बदलता है। यदि आपको अभी भी मूल सरणी की आवश्यकता है तो यह समाधान वह नहीं हो सकता जो आप चाहते हैं। अन्य समाधान इसके बजाय एक नई सरणी बनाते हैं।
एलेक्स

किसी को पता है कि यह ES6 सिंटैक्स में कैसे किया जाता है? मैंने कोशिश की, [arr[j][j],arr[i][j]] = [arr[i][j],arr[j][j]]लेकिन यह काम नहीं कर रहा है, क्या मुझे कुछ याद आ रहा है?
निकस्व

@Nikasv आप संभावना चाहते हैं [arr[j][i], arr[i][j]] = [arr[i][j], arr[j][i]]। ध्यान दें कि आपके पास कुछ arr[j][j]शब्द हैं जो हमेशा विकर्ण पर कोशिकाओं को संदर्भित करेंगे।
एल्गोरिथम कैनरी

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

ट्रांसपोज़िंग के लिए सभी तत्व कॉलम-पहले मैपिंग है, और फिर पंक्ति द्वारा।


5

यदि आपके पास रामा जेएस और ईएस 6 सिंटैक्स का उपयोग करने का विकल्प है, तो यहां एक और तरीका है:

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
इसे हल करने के लिए रामदा और ईएस 6 दोनों का उपयोग करने के लिए
जागृति

1
Ramda वास्तव में एक है transposeसमारोह अब।
याकूब लॉरिटजन

5

आंतरिक मानों की मैपिंग करके मैट्रिक्स को बाहर से अंदर तक कम करने और मैट्रिक्स को कम करके एक और दृष्टिकोण।

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


वास्तव में! आपने @Andrew Tatomyr उत्तर अनुकूलित किया है! (बेंचमार्क आपके पक्ष में काम करते हैं!)
scraaappy

4

यदि RamdaJS का उपयोग करना एक विकल्प है, तो इसे एक पंक्ति में प्राप्त किया जा सकता है: R.transpose(myArray)


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

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

यहाँ एक डेमो है जो मैंने एक साथ फेंका है। छोरों की कमी पर ध्यान दें :-)

// 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>


आप इसे बिना छोरों के क्यों नहीं करना चाहेंगे? लूप्स के बिना यह धीमा है
डाउनगेट

5
एक लूप को खोलना नहीं है? बस एक तुम नहीं देखते हो? मेरा मतलब है कि यह हर इनपुट पर जा रहा है और इसमें सामान है ...
जूलिक्स

2

ES6 1 लीनर्स के रूप में:

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

इतना ही'sscar का है, लेकिन जैसा कि आप इसे दक्षिणावर्त घुमाएंगे:

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

2

संपादित करें: यह उत्तर मैट्रिक्स को स्थानांतरित नहीं करेगा, बल्कि इसे घुमाएगा। मैंने प्रश्न को पहले ध्यान से नहीं पढ़ा: डी

दक्षिणावर्त और वामावर्त घुमाव:

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

हालांकि, सवाल का जवाब नहीं देता; ट्रांसपोज़िंग की तरह है ... विकर्ण के साथ प्रतिबिंबित (घूर्णन नहीं)
DerMike

@DerMike इशारा करने के लिए धन्यवाद। मुझे नहीं पता कि मैंने वह गलती क्यों की है :) लेकिन कम से कम मैं देख सकता हूं कि यह कुछ अन्य लोगों के लिए उपयोगी है।
आर्यन फिरोजियन 10

यहां मैट्रिक्स को घुमाने के लिए मेरा एक-लाइनर कोड है: stackoverflow.com/a/58668351/741251
नितिन जाधव

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
}

1

मुझे लगता है कि यह थोड़ा अधिक पठनीय है। यह 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);



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

0

टाइपस्क्रिप्ट में एक पुस्तकालय-मुक्त कार्यान्वयन जो किसी भी मैट्रिक्स आकार के लिए काम करता है जो आपके सरणियों को छोटा नहीं करेगा:

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

0

एक-लाइनर जो दी गई सरणी को नहीं बदलता है।

a[0].map((col, i) => a.map(([...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]));
}

3
कृपया केवल कोड को एक उत्तर के रूप में पोस्ट न करें, लेकिन एक स्पष्टीकरण शामिल करें कि आपका कोड क्या करता है और यह प्रश्न की समस्या को कैसे हल करता है। एक स्पष्टीकरण के साथ उत्तर आम तौर पर उच्च गुणवत्ता और upvotes को आकर्षित करने की अधिक संभावना है।
मार्क रोटेटेवेल

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

0

चूँकि यहाँ अब तक किसी ने भी कार्यात्मक पुनरावर्ती दृष्टिकोण का उल्लेख नहीं किया है। हास्केल का एक अनुकूलन 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
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.