Каков хороший способ определить, что метод вызывается с разными параметрами?

#typescript

Вопрос:

Допустим, у нас есть метод, который мы хотели бы, чтобы он возвращал тот же последний результат, если ни один из его параметров не изменился с момента последнего вызова. Как мы должны проверить, не изменились ли его параметры? Кэшировать параметры в объекте? массив? для более поздней проверки.

 Compute( p1:boolean, p2:number, p3:number) {
 // if any of p1 or p2 or p3 have changed from last invocation 
 // then redo computation
 // else return last result. 
}
 

В прошлом, когда я имел дело с одним параметром, я использовал поле типа p1_last и сравнивал его с ним при вводе.
что-то вроде этого

   if (p1 == this.p1_last) {
    return this.result
  }
  else {
    this.p1_last = p1 // save p1 for next invocation.
    result = ....some algo....
    return this.result
  }
 

Ваши мысли и предложения оценены по достоинству. Спасибо.

Ответ №1:

Если количество параметров фиксировано, проверка массива должна быть тривиальной:

 let lastParams: [boolean, number, number];
let lastResu< // type this properly...
function Compute( p1:boolean, p2:number, p3:number) {
  if (
    lastParams amp;amp;
    lastParams[0] === p1 amp;amp;
    lastParams[1] === p2 amp;amp;
    lastParams[2] === p3
  ) {
    return lastResu<
  }
  lastResult = /* some computation */
  lastParams = [p1, p2, p3];
  return lastResu<
}
 

Ответ №2:

Вы можете создать общую функцию, которая запоминает входные данные для переданной функции.

 function memorize<F extends (...args: any) => any>(func: F): F {
  const cache = new Map()
  
  return function (this: unknown, ...args: unknown[]): unknown {
    // update the key calculation according to type of args
    const argsKey = args.toString()
    const cacheValue = cache.get(argsKey)
    
    if (cacheValue) console.log('cache working')
    if (cacheValue) return cacheValue
    
    const result = func.apply(this, args)
    cache.set(argsKey, result)
    
    return result
  } as F
}

let compute = function (p1: boolean, p2: number, p3: number) {
  // sample computation
  if (p1) return p2 * p3
  return p2   p3
}

compute = memorize(compute)

let x = compute(true, 1, 2)
console.log(x)
x = compute(true, 1, 2) // cached
console.log(x)
x = compute(false, 1, 2)
console.log(x)
x = compute(false, 1, 2) // cached
console.log(x)
x = compute(false, 3, 2)
console.log(x)
x = compute(false, 3, 2) // cached
console.log(x)
x = compute(true, 1, 2) // cached
console.log(x)
 

Игровая площадка

Комментарии:

1. Ух ты! интересное решение, у вас, наверное, антенны на макушке 🙂 Мне нужно потратить час, чтобы понять весь тот синтаксис запоминания, который вы использовали 🙂 но я своего рода программист, который использует вещи в черных ящиках. Это, вероятно, неприменимо к большим данным, возможно, излишне в моей ситуации. Мне нравится, как после вычисления = запоминания(вычисления) вы как бы переопределяете вычисления, и использование естественно. Я приму это как решение/ответ, поскольку я могу использовать его в будущем. Спасибо вам за то, что поделились своими знаниями.

2. @Meryan Добро пожаловать! Возможно, вам потребуется внести изменения const str = args.toString() в соответствии с вашим вариантом использования и в зависимости от типа параметров func , которые вы можете использовать. Немного обновлен ответ!

Ответ №3:

Как насчёт

 private ComputeLastParams = {}
private ResultLast 
Compute( p1:boolean, p2:number, p3:number) {
  if ( ObjectEqual ( {p1, p2, p3}, this.ComputeLastParams )
  ) {
    return this.ResultLast 
  }
  //
  this.ResultLast = /* some computation */
  this.ComputeLastParams = {p1, p2, p3}
  return this.ResultLast 
}
 
 static ObjectEqual(object1, object2) {
        const keys1 = Object.keys(object1);
        const keys2 = Object.keys(object2);

        if (keys1.length !== keys2.length) {
            return false;
        }

        for (let key of keys1) {
            if (object1[key] !== object2[key]) {
                return false;
            }
        }

        return true;
    }