tiagomnf
tiagomnf

Reputation: 25

Transpose irregular matrix in JavaScript

I got this matrix that, depending on the results I receive from the server, the width can change. Basically, it can be something like

[undefined, undefined]
[1, 2, 3, 4]
[1, 2]
[undefined, undefined, undefined]
[1, 2, 3, 4, 5, 6]

and I want it to be like this

[undefined, 1, 1, undefined, 1]
[undefined, 2, 2, undefined, 2]
[undefined, 3,undefined, undefined, 3]
[undefined, 4, undefined, undefined, 4]
[undefined, undefined, undefined, undefined, 5]
[undefined, undefined, undefined, undefined, 6]

Notice that the height changed to the maximum width of the first example. I googled it and the best solution I got was this

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

but this solution wont change my matrix height. I tried 2 for cycles but I think I didn't code it right as I was not getting the expected result. If someone could give me a little help, that would be awesome

Upvotes: 0

Views: 897

Answers (4)

Igor Sukharev
Igor Sukharev

Reputation: 3118

The more efficient solution:

const maxLength2d = (matrix) => {
  let result = 0

  for (const { length } of matrix) result = Math.max(result, length)

  return result
}

const transpose2d = (matrix, placeholder = undefined) => {
  const result = []
  const maxlen = maxLength2d(matrix)
  let y = 0

  for (const { length } = matrix; y < length; y++) {
    const inner = matrix[y]
    let x = 0

    for (const { length } = inner; x < length; x++) {
      result[x] ||= []
      result[x].push(inner[x])
    }

    for (; x < maxlen; x++) {
      result[x] ||= []
      result[x].push(placeholder)
    }
  }

  return result
}

const transposed = transpose2d(
  [
    [1, 2],
    ['a', 'b', 'c', 'd'],
  ]
)

console.log('transposed', transposed)

console.log('transposed back', transpose2d(transposed))

Upvotes: 0

Keith
Keith

Reputation: 24181

There are a few steps involved here.

  1. Find the max length.

  2. Normalise

  3. And then rotate

I've placed comments in code to show each part.

const input = [
  [undefined, undefined],
  [1, 2, 3, 4],
  [1, 2],
  [undefined, undefined, undefined],
  [1, 2, 3, 4, 5, 6]
];

//first find max length
const maxw = Math.max(...input.map(m => m.length));

//now normalize
const norm_inputs = input.map(m => 
  (new Array(maxw)).concat(m).slice(-maxw)
);

//now rotate..
const output = (new Array(maxw).fill(0)).map(
  (row, i) => norm_inputs.map(col => col[i]))

Upvotes: 0

shreyasminocha
shreyasminocha

Reputation: 548

Assuming your matrix is stored in matrix,

const transformed = [];

const maxWidth = matrix.reduce((max, current) => {
    return (current.length > max) ? current.length : max;
}, 0);

// Loop over each column
for (let i = 0; i < maxWidth; i++) {
    const tRow = [];

    // Loop over each row of the current column
    for (const row of matrix) {
        tRow.push(row[i]);
    }

    transformed.push(tRow);
}

Upvotes: 0

Jordan Running
Jordan Running

Reputation: 106017

There are a lot of ways to solve this (as other answers demonstrate). Here's how I'd do it, as it minimizes the number of times we iterate over the data.

const data = [
  [undefined, undefined],
  [1, 2, 3, 4],
  [1, 2],
  [undefined, undefined, undefined],
  [1, 2, 3, 4, 5, 6],
];

// get the length of the longest array
const maxLen = data.reduce((max, {length}) => Math.max(max, length), 0);

// make a new set of arrays
const result = Array.from({ length: maxLen }, (_, i) => data.map(col => col[i]));

console.log(result);

Upvotes: 4

Related Questions