|
| 1 | +This exercise introduces: |
| 2 | +- String reader via [`String#split`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split) |
| 3 | +- [`Array#map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) |
| 4 | + |
| 5 | +### Reasonable solutions |
| 6 | + |
| 7 | +There are two ways to transpose the matrix. Either non-destructive: |
| 8 | + |
| 9 | +```typescript |
| 10 | +function transpose<T>(rows: Readonly<T[][]>): T[][] { |
| 11 | + return rows[0].map((_, i) => { |
| 12 | + return rows.map((row) => { |
| 13 | + return row[i] |
| 14 | + }) |
| 15 | + }) |
| 16 | +} |
| 17 | +``` |
| 18 | + |
| 19 | +Or destructive: |
| 20 | + |
| 21 | +```typescript |
| 22 | +function transpose<T>(matrix: T[][]): T[][] { |
| 23 | + for (let i = 0; i < matrix.length; i++) { |
| 24 | + for (let j = 0; j < i; j++) { |
| 25 | + [matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]] |
| 26 | + } |
| 27 | + } |
| 28 | + return matrix |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +In case of the latter, the logic becomes harder. Make sure the implementation of |
| 33 | +the student allows for calling both `columns` and `rows` on the same instance, |
| 34 | +multiple times. This is _not_ part of the test suite (yet). This is important if |
| 35 | +the student uses getters for example. |
| 36 | + |
| 37 | +The matrix itself is straight-forward: |
| 38 | + |
| 39 | +```typescript |
| 40 | +class Matrix { |
| 41 | + |
| 42 | + public readonly rows: number[][] |
| 43 | + public readonly columns: number[][] |
| 44 | + |
| 45 | + constructor(input: Readonly<string>) { |
| 46 | + this.rows = input.split('\n').map((row) => row.split(' ').map(Number)) |
| 47 | + this.columns = transpose(this.rows) |
| 48 | + } |
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +A student may use `parseInt` instead of `number`, and a student may use getters |
| 53 | +(`get rows() { return this.data }`) to make the transposing lazy. |
| 54 | + |
| 55 | +### Common suggestions |
| 56 | +- If a student uses `foreach`, intermediary bookkeeping and `push`, suggest [`Array#map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). |
| 57 | +- If a student uses a dangerous version of transpose, suggest a non-destructive one, or make sure it's only ever called once. |
| 58 | +- If a student uses `map(arg => parseInt(arg))` or similar, explain they can drop the anonymous arrow function and pass in `parseInt` directly. |
| 59 | +- If a student uses `any[][]`, point them towards `name<T>(arg: Readonly<T[][]>): T[][]` which preserves the type of the arrays |
| 60 | +- If a student builds both array in one go, as shown below this suggestion, suggest `Array#map` and point them to "transpose algorithm": |
| 61 | + |
| 62 | +```javascript |
| 63 | +const rows: number[][] = [] |
| 64 | +const columns: number[][] = [] |
| 65 | + |
| 66 | +input.split('\n') |
| 67 | + .forEach((row, i) => { |
| 68 | + this.rows.push(row.split(' ').map(Number)) |
| 69 | + this.rows[i].forEach( |
| 70 | + i === 0 |
| 71 | + ? (e) => this.columns.push([e]) |
| 72 | + : (e, j) => this.columns[j].push((e)) |
| 73 | + ) |
| 74 | + }) |
| 75 | +``` |
| 76 | + |
| 77 | +### Talking points |
| 78 | +- Functions are first class citizens, so you can pass one to `Array#map` and it executes on each one |
| 79 | +- Immutability and side effects |
0 commit comments