pythonmemoization

Memoizing Coin Change


I want to convert my coin change function to memoized function
to do that, I decided to use dictionary so that a key in my dict will be the coin and the value will be a list that contain all the coins that can change the "key" coin.
what I did is:

def change(a,kinds=(50,20,10,5,1)):
    if(a==0):
            return 1
    if(a<0 or len(kinds)==0):
            return 0

    return change(a-kinds[0],kinds)+change(a,kinds[1:])


def memoizeChange(f):
    cache={}
    def memo(a,kinds=(50,20,10,5,1)):

        if len(cache)>0 and kinds in cache[a]:
            return 1
        else:
            if(f(a,kinds)==1):
                cache[a]=kinds // or maybe cache[a].append(..)
                return cache[a]+memo(a-kinds[0],kinds)+memo(a,kinds[1:])
    return memo

memC=memoizeChange(change)
kinds=(50,20,10,5,1)
print(memC(10,kinds))

I would like to get some suggestions , or maybe there is another way to do that.
thanks.


EDIT
Memoized version:

def change(a,kinds=(50,20,10,5,1)):
    if(a==0):
            return 1
    if(a<0 or len(kinds)==0):
            return 0
    return change(a-kinds[0],kinds)+change(a,kinds[1:])


def memoizeChange(f):
    cache={}
    def memo(a,kinds=(50,20,10,5,1)):
        if not (a,kinds) in cache:
                cache[(a,kinds)]=f(a,kinds)
        return cache[(a,kinds)]
    return memo

change=memoizeChange(change)
print(change(10))

Solution

  • It's not necessary to write a specialized memorizing decorator when you could just use a generic pre-written one...such as the following straight from the PythonDecoratorLibrary:

    import collections
    import functools
    
    class memoized(object):
       '''Decorator. Caches a function's return value each time it is called.
       If called later with the same arguments, the cached value is returned
       (not reevaluated).
       '''
       def __init__(self, func):
          self.func = func
          self.cache = {}
       def __call__(self, *args):
          if not isinstance(args, collections.Hashable):
             # uncacheable. a list, for instance.
             # better to not cache than blow up.
             return self.func(*args)
          if args in self.cache:
             return self.cache[args]
          else:
             value = self.func(*args)
             self.cache[args] = value
             return value
       def __repr__(self):
          '''Return the function's docstring.'''
          return self.func.__doc__
       def __get__(self, obj, objtype):
          '''Support instance methods.'''
          return functools.partial(self.__call__, obj)
    

    You could then apply it to yourchange()function (or any other, since it's generic) like this:

    @memoized
    def change(a, kinds=(50, 20, 10, 5, 1)):
        if a == 0:
            return 1
        if a < 0 or len(kinds) == 0:
            return 0
    
        return change(a - kinds[0], kinds) + change(a, kinds[1:])
    
    print(change(10))  # 4