This exercise introduces:
- String reader via
String#split
Array#map
There are two ways to transpose the matrix. Either non-destructive:
function transpose(rows) {
return rows[0].map((_, i) => {
return rows.map((row) => {
return row[i]
})
})
}
Or destructive:
function transpose(matrix) {
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < i; j++) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]]
}
}
return matrix
}
In case of the latter, the logic becomes harder. Make sure the implementation of
the student allows for calling both columns
and rows
on the same instance,
multiple times. This is not part of the test suite (yet). This is important if
the student uses getters for example.
The matrix itself is straight-forward:
export class Matrix {
constructor(input) {
this.rows = input.split('\n').map((row) => row.split(' ').map(Number))
this.columns = transpose(this.rows)
}
}
A student may use parseInt
instead of number
, and a student may use getters
(get rows() { return this.data }
) to make the transposing lazy.
- If a student uses
foreach
, intermediary bookkeeping andpush
, suggestArray#map
. - If a student uses a dangerous version of transpose, suggest a non-destructive one, or make sure it's only ever called once.
- If a student uses
map(arg => parseInt(arg))
or similar, explain they can drop the anonymous arrow function and pass inNumber
function directly, but notparseInt
because that accepts two arguments andArray#map
passes item index implicitly. - If a student builds both array in one go, as shown below this suggestion, suggest
Array#map
and point them to "transpose algorithm":
const rows = []
const columns = []
input.split('\n')
.forEach((row, i) => {
this.rows.push(row.split(' ').map(Number))
this.rows[i].forEach(
i === 0
? (e) => this.columns.push([e])
: (e, j) => this.columns[j].push((e))
)
})
- Functions are first class citizens, so you can pass one to
Array#map
and it executes on each one - Immutability and side effects