From 2fd0d3ea58f74ca1b09d12204e2fb5d091dd5575 Mon Sep 17 00:00:00 2001 From: Luke Manyamazi Date: Mon, 10 Nov 2025 11:27:27 +0200 Subject: [PATCH 1/2] Implement LRU cache and tests --- Sprint-2/implement_lru_cache/lru_cache.py | 35 ++++++++++++++++ .../implement_lru_cache/lru_cache_test.py | 40 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/Sprint-2/implement_lru_cache/lru_cache.py b/Sprint-2/implement_lru_cache/lru_cache.py index e69de29..4069e12 100644 --- a/Sprint-2/implement_lru_cache/lru_cache.py +++ b/Sprint-2/implement_lru_cache/lru_cache.py @@ -0,0 +1,35 @@ +class LruCache: + def __init__(self, limit): + if limit <= 0: + raise ValueError("Limit must be greater than 0") + + self.limit = limit + self.cache = {} + self.access_order = [] # most recent at the end + + def get(self, key): + if key in self.cache: + # Move to most recent position + self.access_order.remove(key) + self.access_order.append(key) + return self.cache[key] + return None + + def set(self, key, value): + if key in self.cache: + # Update existing key + self.cache[key] = value + # Move to most recent position + self.access_order.remove(key) + self.access_order.append(key) + else: + # New key + if len(self.cache) >= self.limit: + # Remove least recently used (first item) + lru_key = self.access_order[0] + del self.cache[lru_key] + self.access_order.pop(0) + + # Add new key as most recent + self.cache[key] = value + self.access_order.append(key) \ No newline at end of file diff --git a/Sprint-2/implement_lru_cache/lru_cache_test.py b/Sprint-2/implement_lru_cache/lru_cache_test.py index d37df01..314da14 100644 --- a/Sprint-2/implement_lru_cache/lru_cache_test.py +++ b/Sprint-2/implement_lru_cache/lru_cache_test.py @@ -54,6 +54,46 @@ def test_eviction_order_after_gets(self): self.assertEqual(cache.get("a"), 1) self.assertEqual(cache.get("c"), 3) + def test_get_refreshes_item(self): + """Test that getting an item makes it recently used""" + cache = LruCache(limit=2) + + cache.set("a", 1) + cache.set("b", 2) + + # Access "a" to make it recently used + cache.get("a") + + # Add new item - should evict "b" not "a" + cache.set("c", 3) + + self.assertIsNone(cache.get("b")) # "b" was evicted + self.assertEqual(cache.get("a"), 1) # "a" remains + self.assertEqual(cache.get("c"), 3) + + def test_complex_usage_pattern(self): + """Test LRU behavior with multiple operations""" + cache = LruCache(limit=3) + + # Add initial items + cache.set("a", 1) + cache.set("b", 2) + cache.set("c", 3) + + # Use items in various order + cache.get("a") + cache.get("c") + cache.get("b") + cache.get("a") + + # Add new item - should evict least recently used ("c") + cache.set("d", 4) + + self.assertIsNone(cache.get("c")) # "c" was evicted + self.assertEqual(cache.get("a"), 1) + self.assertEqual(cache.get("b"), 2) + self.assertEqual(cache.get("d"), 4) + if __name__ == "__main__": unittest.main() From 2692da2d80a230e3f40ad7ab710d09a4bff05f25 Mon Sep 17 00:00:00 2001 From: Luke Manyamazi Date: Fri, 13 Feb 2026 18:15:07 +0200 Subject: [PATCH 2/2] Refactor LRU cache to use OrderedDict for O(1) operations --- .gitignore | 3 +- Sprint-2/implement_lru_cache/lru_cache.py | 42 +++++++++-------------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index bfb5886..6127881 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store -node_modules +node_modules/ .venv __pycache__ +venv/ diff --git a/Sprint-2/implement_lru_cache/lru_cache.py b/Sprint-2/implement_lru_cache/lru_cache.py index 4069e12..57bba7b 100644 --- a/Sprint-2/implement_lru_cache/lru_cache.py +++ b/Sprint-2/implement_lru_cache/lru_cache.py @@ -1,35 +1,27 @@ +from collections import OrderedDict + class LruCache: def __init__(self, limit): if limit <= 0: raise ValueError("Limit must be greater than 0") - self.limit = limit - self.cache = {} - self.access_order = [] # most recent at the end - + self.cache = OrderedDict() + def get(self, key): - if key in self.cache: - # Move to most recent position - self.access_order.remove(key) - self.access_order.append(key) - return self.cache[key] - return None + if key not in self.cache: + return None + + # Mark as recently used + self.cache.move_to_end(key) + return self.cache[key] def set(self, key, value): if key in self.cache: - # Update existing key - self.cache[key] = value - # Move to most recent position - self.access_order.remove(key) - self.access_order.append(key) - else: - # New key - if len(self.cache) >= self.limit: - # Remove least recently used (first item) - lru_key = self.access_order[0] - del self.cache[lru_key] - self.access_order.pop(0) - # Add new key as most recent - self.cache[key] = value - self.access_order.append(key) \ No newline at end of file + self.cache.move_to_end(key) + + self.cache[key] = value + + # Evict least recently used item + if len(self.cache) > self.limit: + self.cache.popitem(last=False)