leetcode-lfu-cache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

import collections
import functools
from itertools import filterfalse
from heapq import nsmallest
from operator import itemgetter


class Counter(dict):

def __missing__(self, key):
return 0


def lfu_cache(maxsize=100):

def decorating_function(user_function):
cache = {} # mapping of args to results
use_count = Counter() # times each key has been accessed
kwd_mark = object() # separate positional and keyword args

@functools.wraps(user_function)
def wrapper(*args, **kwds):
key = args
if kwds:
key += (kwd_mark,) + tuple(sorted(kwds.items()))
use_count[key] += 1

# get cache entry or compute if not found
try:
result = cache[key]
wrapper.hits += 1
except KeyError:
result = user_function(*args, **kwds)
cache[key] = result
wrapper.misses += 1

# purge least frequently used cache entry
if len(cache) > maxsize:
for key, _ in nsmallest(maxsize // 10,
use_count.items(),
key=itemgetter(1)):
del cache[key], use_count[key]

return result

def clear():
cache.clear()
use_count.clear()
wrapper.hits = wrapper.misses = 0

wrapper.hits = wrapper.misses = 0
wrapper.clear = clear
return wrapper
return decorating_function


if __name__ == '__main__':

@lfu_cache(maxsize=20)
def f(x, y):
return 3 * x + y

domain = range(5)
from random import choice
for i in range(1000):
r = f(choice(domain), choice(domain))

print(f.hits, f.misses)