Skip to content

Commit 6656ece

Browse files
authored
merge: Improved Memoize function (#912)
* feat: improved memoize function used Map instead of object & used the JSON.stringfy method for generate a valid string as a key * docs: modified documentation * style: format with standard * docs: modified stringify doc * refactor: remove two repetition implementation
1 parent eb748ae commit 6656ece

File tree

2 files changed

+72
-27
lines changed

2 files changed

+72
-27
lines changed

Cache/Memoize.js

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,60 @@
11
/**
2-
* Memoize
3-
*
2+
* @function memoize
3+
* @description ->
44
* From [Wikipedia](https://en.wikipedia.org/wiki/Memoization),
55
* memoization is an optimization technique
66
* used primarily to speed up computer programs,
77
* by storing the results of expensive function calls
88
* and returning the cached result when the same inputs occur again
9-
*
109
* This function is a first class objects,
1110
* which lets us use it as [Higher-Order Function](https://eloquentjavascript.net/05_higher_order.html)
1211
* and return another function
13-
*
1412
* @param {Function} func Original function
1513
* @returns {Function} Memoized function
1614
*/
17-
export const memoize = (func) => {
18-
// Initialization of a slot to store the function result
19-
const cache = {}
15+
const memoize = (func) => {
16+
// Initialization of a slot to store the function result by arguments as a key in Hash Map
17+
const cache = new Map()
18+
19+
const jsonReplacer = (_, value) => {
20+
if (value instanceof Set) { // if the value is Set it's converted to Array cause JSON.stringify can't convert Set
21+
return [...value]
22+
}
23+
24+
if (value instanceof Map) { // if the value is Map it's converted to Object cause JSON.stringify can't convert Map
25+
return Object.fromEntries(value)
26+
}
27+
28+
return value
29+
}
2030

2131
return (...args) => {
22-
// Retrieving the first argument of the function
23-
const [arg] = args
32+
/**
33+
* Arguments converted to JSON string for use as a key of Map - it's easy to detect collections like -> Object and Array
34+
* If the args input is -> [new Set([1, 2, 3, 4]), {name: 'myName', age: 23}]
35+
* Then the agrsKey generate to -> '[[1,2,3,4],{"name":"myName","age":23}]' which is JSON mean string
36+
* Now it's ready to be a perfect key for Map
37+
*/
38+
const argsKey = JSON.stringify(args, jsonReplacer)
2439

2540
/**
2641
* Checks if the argument is already present in the cache,
2742
* then return the associated value / result
2843
*/
29-
if (arg in cache) {
30-
return cache[arg]
44+
if (cache.has(argsKey)) {
45+
return cache.get(argsKey)
3146
}
3247

3348
/**
3449
* If the argument is not yet present in the cache,
3550
* execute original function and save its value / result in cache,
3651
* finally return it
3752
*/
38-
const result = func(arg)
39-
cache[arg] = result
53+
const result = func(...args) // spread all args
54+
cache.set(argsKey, result)
55+
4056
return result
4157
}
4258
}
59+
60+
export { memoize }

Cache/test/Memoize.test.js

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
import { memoize } from '../Memoize'
2+
import { fibonacci } from '../../Dynamic-Programming/FibonacciNumber'
3+
import { factorial } from '../../Recursive/Factorial'
24

3-
const fibonacci = (n) => {
4-
if (n < 2) {
5-
return n
6-
}
5+
const multipleFactorials = (arr) => arr.map(factorial)
76

8-
return fibonacci(n - 2) + fibonacci(n - 1)
7+
/**
8+
* @title implementation of union function
9+
* @param {Set} sets
10+
* @return {new Set}
11+
*/
12+
function union (...sets) {
13+
return new Set(
14+
sets.reduce((flatArray, set) => [...flatArray, ...set], [])
15+
)
916
}
1017

11-
const factorial = (n) => {
12-
if (n === 0) {
13-
return 1
14-
}
15-
16-
return n * factorial(n - 1)
17-
}
18-
19-
describe('Memoize', () => {
18+
describe('Testing Memoize', () => {
2019
it('expects the fibonacci function to use the cache on the second call', () => {
2120
const memoFibonacci = memoize(fibonacci)
2221

@@ -34,4 +33,32 @@ describe('Memoize', () => {
3433
expect(memoFactorial(10)).toEqual(factorial(10))
3534
expect(memoFactorial(10)).toEqual(3628800)
3635
})
36+
37+
it('expects the multipleFactorials function to use the cache on the second call', () => {
38+
const memoMultipleFactorials = memoize(multipleFactorials)
39+
const input = [2, 3, 4, 5]
40+
41+
expect(memoMultipleFactorials(input)).toEqual([2, 6, 24, 120])
42+
expect(memoMultipleFactorials(input)).toEqual(multipleFactorials(input))
43+
})
44+
45+
it('expects the multipleFactorials function to use the cache on the second call', () => {
46+
const memoMultipleFactorials = memoize(multipleFactorials)
47+
const input = [2, 3, 4, 5]
48+
49+
expect(memoMultipleFactorials(input)).toEqual([2, 6, 24, 120])
50+
expect(memoMultipleFactorials(input)).toEqual(multipleFactorials(input))
51+
})
52+
53+
it('expects the union function to use the cache on the second call', () => {
54+
const memoUnion = memoize(union)
55+
const inputs = [
56+
new Set([1, 2, 3]),
57+
new Set([4, 3, 2]),
58+
new Set([5, 3, 6])
59+
]
60+
61+
expect(memoUnion(...inputs)).toEqual(new Set([1, 2, 3, 4, 5, 6]))
62+
expect(memoUnion(...inputs)).toEqual(union(...inputs))
63+
})
3764
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy