Search code examples
javascriptarraysmatrixmatrix-multiplicationsubtraction

How to subtract these two arrays


I am trying to subtract two matrices, I have a function that takes in those matrices and returns a new matrix that has been subtracted. I get this error in node.js: TypeError: (intermediate value).map is not a function

subtract(a, b) {

  return new Matrix(a.rows, a.cols).map((_, i, j) => a.data[i][j] - b.data[i][j]);
}

This is the function I use from my main file (note: I already have an instance of the class).

let m = new Matrix(2, 2);
m.data[0] = [10, 11];
m.data[1] = [12, 13];

let n = new Matrix(2, 2);
n.data[0] = [1, 2];
n.data[1] = [3, 4];

mat.subtract(m, n);

This is the class that I have created:

class Matrix {
    constructor(rows, cols) {
      this.rows = rows;
      this.cols = cols;
      this.index = 0;
      this.rowCount = 0;
  
      //this.matrixData = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
      this.data = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
    }
}

Solution

  • I'm going to recommend a complete code rewrite that focuses on a plain functions instead of classes and methods. We begin writing our matrix module below and will add an OOP-style interface in the second section of this post. -

    // matrix.js
    
    const matrix = rows =>
      ({ matrix, rows })
    
    const empty = _ =>
      matrix([])
    
    const subtract = (t1, t2) =>
      matrix(t1.rows.map((_, i) => subtractRow(t1.rows[i], t2.rows[i])))
    
    const subtractRow = (r1, r2) =>
      r1.map((v, i) => v - r2[i])
    
    function toString (t)
    { const w =
        Math.max(...t.rows.flat().map(_ => String(_).length))
      const s = 
        t.rows.map(r => r.map(_ => String(_).padStart(w, " ")).join(" "))
      return `[ ${s.join("\n  ")} ]`
    }
    
    export { empty, matrix, subtract, toString } 
    

    Next we write our main module that uses the matrix module -

    // main.js
    
    import { matrix, subtract, toString } from "./matrix.js"
    
    const m1 = matrix([[10, 11], [12, 13]])
    const m2 = matrix([[1,2], [3,4]])
    
    console.log(toString(m1))
    console.log(toString(m2))
    console.log(toString(subtract(m1, m2)))
    
    [ 10 11
      12 13 ]
    
    [ 1 2
      3 4 ]
    
    [ 9 9
      9 9 ]
    

    If you are more comfortable with an OOP-style interface, you we can add that to our matrix module easily. Notice how our Matrix class it is a simple wrapper around our existing plain functions -

    // matrix.js (continued)
    
    class Matrix
    { constructor(t = empty())
      { this.t = t }
    
      subtract(other)
      { return new Matrix(subtract(this.t, other.t)) }
    
      toString()
      { return toString(this.t) }
    
      static of(rows)
      { return new Matrix(matrix(rows)) }
    }
    
    export default Matrix
    

    And here's our main module using our new Matrix interface -

    // main.js
    
    import Matrix from "./matrix.js"
    
    const m1 = Matrix.of([[10, 11], [12, 13]])
    const m2 = Matrix.of([[1,2], [3,4]])
    
    console.log(m1.toString())
    console.log(m2.toString())
    console.log(m1.subtract(m2).toString())
    
    [ 10 11
      12 13 ]
    
    [ 1 2
      3 4 ]
    
    [ 9 9
      9 9 ]
    

    Chain for days, if you wish -

    console.log(m1.subtract(m2).subtract(m2).toString())
    console.log(m2.subtract(m1).subtract(m1).subtract(m1).toString())
    
    [ 8 7
      6 5 ]
    
    [ -29 -31
      -33 -35 ]
    

    As you can see we only write our matrix module once and it is flexible enough to use in functional-style and OOP-style. To see this module technique used in another setting, see this answer where we build a linked list.


    Wondering why we went through so much trouble in matrix.toString? It's so that the matrix can be nicely formatted even when element sizes differ -

    import { matrix, toString } from "./matrix.js"
    
    const m3 = matrix([
      [1,2,3],
      [11,22,33]
      [111,222,333]
    ])
    
    console.log(toString(m3))
    
    [   1   2   3
       11  22  33
      111 222 333 ]