【问题标题】:How to memoize with Map()如何使用 Map() 进行记忆
【发布时间】:2022-11-03 20:05:23
【问题描述】:

我目前遇到了 JavaScript 中 memoize 函数的问题。最后 2 次测试未通过。我会更乐意提供帮助。

问题如下:

  • 编写一个 memoize 函数,该函数接受一个必需的回调函数和一个可选的解析器函数。 memoize 函数返回回调函数的 memoized 版本,定义如下:

  • memoized 函数的所有返回值都被缓存。如果使用现有缓存键(定义如下)调用 memoized 回调,则返回该缓存值而无需再次调用回调。

  • 缓存键是根据可选的解析器函数定义的。如果未提供解析器函数,则缓存键是将记忆函数参数作为数组传递给 JSON.stringify 的结果。如果提供了自定义解析器函数,则应将参数单独传递给该函数,其返回值将是缓存键(请注意,它可以是任何类型)。

  • memoized 函数也应该有三个方法: clear():清除缓存。 delete(...args):如果存在,则删除与传递的参数对应的缓存条目。 has(...args):如果缓存有对应于传递参数的条目,则返回布尔值 true,否则返回 false。为简单起见,您无需担心绑定 this 上下文(即,您可以假设回调不引用 this)。

回调函数如下所示:

const callback = (...args) => args;

这是应该返回的输入和结果

const memoized = memoize(callback);
memoized(123); // calls callback, returns 123
memoized(123); // returns 123
memoized(123, 'abc'); // calls callback, returns [123, 'abc']
const memoized2 = memoize(callback, args => args[0]);
memoized2(123); // calls callback, returns 123
memoized2(123); // returns 123
memoized2(123, 'abc'); // returns 123
memoized('abc', 123); // calls callback, returns ['abc', 123]
memoized2('abc'); // returns ['abc', 123]

我已将所有参数存储在缓存中,当调用相同的参数时,将从缓存中返回结果。

这是我的代码

function memoize(cb) {
    const memo = new Map();

    return function (...args) {
        const key = JSON.stringify(args);
        if (!memo.has(args)) {
            memo.set(key, cb(...args));
            return memo.get(key);
        }
        return memo.get(key);
    };
}

这是测试

const chai = require("chai");
const spies = require("chai-spies");
const { expect } = chai;

chai.use(spies);
const spy = () => chai.spy(() => {});

const { memoize } = require("../memoize.js");

describe("memoize", () => {
    it("callback without parameters is never called twice", () => {
        const callback = spy(() => {});
        const memoized = memoize(callback);
        expect(callback).to.have.been.called.exactly(0);
        memoized();
        expect(callback).to.have.been.called.exactly(1);
        memoized();
        expect(callback).to.have.been.called.exactly(1);
        memoized();
        memoized();
        expect(callback).to.have.been.called.exactly(1);
    });

    it("callback with a single parameter is handled properly", () => {
        const callback = spy((val) => val * 2);
        const memoized = memoize(callback);
        expect(callback).to.have.been.called.exactly(0);
        const val1 = memoized(1);
        expect(callback).to.have.been.called.exactly(1);
        expect(val1).to.equal(2);

        const val2 = memoized(1);
        expect(callback).to.have.been.called.exactly(1);
        expect(val2).to.equal(2);

        const val3 = memoized(2);
        expect(callback).to.have.been.called.exactly(2);
        expect(val3).to.equal(4);

        const val4 = memoized(2);
        expect(callback).to.have.been.called.exactly(2);
        expect(val4).to.equal(4);

        const val5 = memoized(1);
        expect(callback).to.have.been.called.exactly(2);
        expect(val5).to.equal(2);
    });

    it("has function works as expected", () => {
        const callback = spy((...args) => args);
        const memoized = memoize(callback);

        expect(memoized.has()).to.be.false;
        expect(memoized.has(123)).to.be.false;
        expect(memoized.has(123, "abc")).to.be.false;

        memoized();
        expect(memoized.has()).to.be.true;

        memoized(123);
        expect(memoized.has(123)).to.be.true;

        memoized(123, "abc");
        expect(memoized.has(123, "abc")).to.be.true;

        expect(callback).to.have.been.called.exactly(3);
    });
});

【问题讨论】:

  • 您的 memoize() 函数没有可选的解析器
  • if (!memo.has(args)) - 两个数组永远不会相同 - 无论它们的内容如何。你必须测试key
  • @Andreas 我试图将解析器包含在扩展运算符中。例如 (...cb)。然后我检查 cb[1] 是否存在,如果存在,则解析器用于他的目的。但没有什么不同。测试是我的暗示,关于 fn 应该如何工作。
  • 如果你正在做memo.set(key, cb(...args));memo.get(key);,那么memo.has(args) 肯定应该是memo.has(key),否则代码没有任何意义。

标签: javascript function caching callback memoization


【解决方案1】:

我要给出的解决方案解决了 12 个测试而不是 3 个,包括您的测试。

尝试这个:

const defaultResolver = (...args) => JSON.stringify(args);

export function memoize(fn, resolver = defaultResolver) {
  const cache = new Map();
  const memoized = (...args) => {
    const key = resolver(...args);
    if (cache.has(key)) {
      return cache.get(key);
    }
    const result = fn(...args);
    cache.set(key, result);
    return result;
  };
  memoized.clear = () => cache.clear();
  memoized.delete = (...args) => {
    const key = resolver(...args);
    cache.delete(key);
  };
  memoized.has = (...args) => {
    const key = resolver(...args);
    return cache.has(key);
  }
  return memoized;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-04
    • 2016-02-11
    • 2019-11-03
    • 2021-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    相关资源
    最近更新 更多