Memoize

Easy ImportantExpedia

Prompt

Your task is to write a JavaScript function named memoize. This function should take in another function as an argument and return a memoized version of it.

Solution

Explanation 🧠

  • The memoize function is a higher-order function that takes another function fn as an argument.

  • Inside the memoize function, an empty Map instance cache is created, which will be used to store the memoized results.

  • The memoize function returns a new function using an arrow function syntax.

  • Inside the returned function, the arguments passed to the function are stringified using JSON.stringify to create a key for the cache Map.

  • If the key exists in the cache Map (checked using cache.has(key)), it means the function has been called with those arguments before, so it simply returns the cached result from the Map using cache.get(key).

  • If the key doesn't exist in the cache Map, it means the function hasn't been called with those arguments before, so it calls the original function fn with the given arguments using the spread syntax fn(...args), stores the result in the cache Map using cache.set(key, result), and returns the result.

  • The first time memoizedSquare(140) is called, the memoized function doesn't find the result in the cache object, so it calls the original square function with 140 as the argument, calculates the result, stores it in the cache object, and returns the result.

  • The second and third times memoizedSquare(140) is called, the memoized function finds the result in the cache object using the key "140", and it simply returns the cached result without calling the original square function again.

The Map provides better performance for key-value storage and retrieval compared to objects, especially when dealing with non-string keys.

⬆️ Level up #1 (Measure Performance)

How can you measure the time taken by each operation to evaluate the effectiveness of memoization?

Solution

Explanation 🧠

To evaluate the benefits of memoization, one can use the console.time() and console.timeEnd() functions to compare the duration of operations conducted with and without the application of memoization. For instance, in the example provided above, we are calculating the square of a number. The initial computation requires a significant amount of time because the result isn't initially cached. However, if one inspects the console logs, they'll notice that subsequent computations are considerably quicker. This speed is due to the results now being stored in the cache, enabling the function to retrieve them directly from the cache rather than recomputing them.

Note 📄

Imagine you're cooking Palak Paneer, a delicious Indian vegetarian dish, and you want to time how long it takes. Here's how you'd do it:

  • Start the stopwatch when you begin cooking. In our code, we'll call console.time('Cooking Palak Paneer')
  • Cook your dish. In the JavaScript world, this represents any task you want to time. It could be a complex calculation, loading data, or anything that requires time to complete.
  • Stop the stopwatch when you finish. In the code, you'll call console.timeEnd('Cooking Palak Paneer')
console.time('Cooking Palak Paneer'); // Start the stopwatch (or timer)

// This is where you "cook" in your code, i.e., perform the operation you're timing.
for (let i = 0; i < 100000; i++) {
// Here, we're just looping many times as a placeholder for the cooking process.
}

console.timeEnd('Cooking Palak Paneer'); // Stop the stopwatch (or timer)

When you run this code, the console (think of it as your digital kitchen timer) will tell you how long it took to "cook the Palak Paneer". You'll see a message something like this: "Cooking Palak Paneer: 35ms". This means it took 35 milliseconds to run the code between the start and end commands. Keep in mind this is a simple example, and the real process of cooking Palak Paneer is a lot more enjoyable! 🍽️ 💖

00:00