JAVASCRIPT
Binary Search Tree
Insert, search, and delete while keeping values sorted. Average O(log n), worst O(n) if the tree becomes a chain.
Wrap a function and reuse its result for the same inputs. The next call with the same values skips the work.
function memoize(fn, keyOf = defaultKey) {
const cache = new Map();
function wrapped(...args) {
const key = keyOf(...args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
if (isThenable(result)) {
Promise.resolve(result).catch(function () {
cache.delete(key);
});
}
return result;
}
wrapped.clear = function () {
cache.clear();
};
return wrapped;
}
function defaultKey(...args) {
return args.map(function (value) {
if (value === null) {
return 'null';
}
const type = typeof value;
if (type === 'string') {
return 's:' + value;
}
if (type === 'number') {
return 'n:' + String(value);
}
if (type === 'boolean') {
return 'b:' + String(value);
}
if (type === 'bigint') {
return 'i:' + String(value);
}
if (type === 'undefined') {
return 'undefined';
}
if (type === 'object') {
return 'o:' + JSON.stringify(value);
}
return type + ':' + String(value);
}).join('|');
}
function isThenable(value) {
return value != null && typeof value.then === 'function';
}
function memoizeWeak(fn) {
const cache = new WeakMap();
return function (object, ...rest) {
if (object == null || typeof object !== 'object') {
throw new TypeError('First argument must be an object');
}
let inner = cache.get(object);
if (!inner) {
inner = new Map();
cache.set(object, inner);
}
const key = defaultKey(...rest);
if (inner.has(key)) {
return inner.get(key);
}
const result = fn.apply(this, [object, ...rest]);
inner.set(key, result);
return result;
};
}
const fibonacci = memoize(function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(40));
console.log(fibonacci(40)); // from cache
fibonacci.clear();
const area = memoize(function (width, height) {
return width * height;
});
console.log(area(4, 5));
console.log(area('4', 5)); // different key from 4, 5
A practical place for this snippet in a real project.
Useful for a repeated calculation with the same inputs, or a request that runs more than once in the same session. It is not a store for data that must stay fresh.
Insert, search, and delete while keeping values sorted. Average O(log n), worst O(n) if the tree becomes a chain.
Keep a fixed number of entries and evict the least recently used item when the cache is full.
An undirected graph: visit in breadth or depth, find the shortest hop path, and detect a cycle without counting the walk back to a parent.
Describe the problem or idea, and I will see if it belongs in the library.