0

I have a bulk operation that operates on a 2 dimensional array. It shall call a given method "func" on each element in the array:

function forEachMatrixElement(matrix: Complex[][], func: Function): Complex[][] {
  let matrixResult: Complex[][] = new Array(countRows(matrix)).fill(false).map(() => new Array(countCols(matrix)).fill(false)); // Creates a result 2D-Matrix
  for (let row = 0; row < countRows(matrix); row++) {
    for (let col = 0; col < countCols(matrix); col++) {
      matrixResult[row][col] = func.call(matrix[row][col]); // Call the given method
    }
  }
  return matrixResult;
}

I have two functions that I want to delegate to this method: This one takes no additional arguments and works fine:

export function conjugateMatrix(matrix: Complex[][]): Complex[][] {
  return forEachMatrixElement(matrix, Complex.prototype.conjugate);
}

This one takes an additional argument (a scalar). But I don't know how to add this argument to this method reference on the prototype:

export function multiplyMatrixScalar(matrix: Complex[][], scalar: Complex): Complex[][] {
  return forEachMatrixElement(matrix, Complex.prototype.mul); // TODO Call with scalar
}

3 Answers 3

2

Reaching into the prototype and manipulating the value of this with call() is usually a bad idea. This can be made simpler.

Instead, the forEachMatrixElement should simply take a function that accepts a Complex instance, and the caller can decide what that function does and how to apply its arguments.

For example:

function forEachMatrixElement(
  matrix: Complex[][],
  func: (complex: Complex) => Complex // Changed this function type
): Complex[][] {
  let matrixResult: Complex[][] = new Array(countRows(matrix)).fill(false).map(() => new Array(countCols(matrix)).fill(false));
  for (let row = 0; row < countRows(matrix); row++) {
    for (let col = 0; col < countCols(matrix); col++) {
     
      // just invoke the function like any other. No .call()
      matrixResult[row][col] = func(matrix[row][col]); 
      
    }
  }
  return matrixResult;
}

Now the functions that call this can simply be:

export function conjugateMatrix(matrix: Complex[][]): Complex[][] {
  return forEachMatrixElement(matrix, (c) => c.conjugate());
}

export function multiplyMatrixScalar(matrix: Complex[][], scalar: Complex): Complex[][] {
  return forEachMatrixElement(matrix, (c) => c.mul(scalar));
}

See Playground

Sign up to request clarification or add additional context in comments.

1 Comment

Also I think your forEachMatrixElement() can be much simpler with some simple map() calls. tsplay.dev/NrXJaW
2

Could you just create a new function in multiplyMatrixScalar?

Something like:

export function multiplyMatrixScalar(matrix: Complex[][], scalar: Complex): Complex[][] {
  const fn = function (this: Complex) { return this.mul(c, scalar)};

  return forEachMatrixElement(matrix, fn);
}

4 Comments

So something like const fn = (c: Complex) => c.mul(scalar); for the function then?
Or I guess it would be const fn = function(this: Complex) { this.mul(scalar); } if you're using .call
Return is missing. But the answer is correct. Thank you. Would you like to complete it?: const fn = function(this: Complex) { return this.mul(scalar); }
Right you are, thank you. I'll update the answer.
0

MDN Function.call() can take additional parameters as arguments. So the first parameter will always be the this bind, the second and onwards are arguments.

Wonder if this is what will solve your issue? So your code will look like

function forEachMatrixElement(matrix: Complex[][], func: Function, scalar?: Complex)

and

func.call(matrix[row][col], scalar)

1 Comment

I don't want to add additional arguments to forEachMatrixElement. The provided function func has to be complete

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.