I've written a program that essentially does Fibonacci by reading from a dictionary that it creates (given {0:0, 1:1} to start). Obviously if it doesn't have it in the dictionary, it will create until it does, and then later calls so it doesn't have to do the same sequence over and over again. What I'm having difficulty with is using the Counter object to keep track of the instructions done by the algorithm (so I can afterwards plot the graph of how many calls as the initial n increases). Never used class Counter before or memoization so I'm a bit lost here at the end.
dic = {0:0, 1:1}
def main():
n = int(input("Number to Fibonacci?"))
fib(n)
print(dic[n])
Counter()
memoization(n, Counter, dic)
def fib(n):
if n in dic:
return dic[n]
else:
if n < 2:
dic[n] = n
else:
dic[n] = fib(n-2) + fib(n-1)
return dic[n]
class Counter():
def __init__(self):
self._number = 0
def increment(self):
self._number += 1
def __str__(self):
return str(self._number)
def print():
print(str(self._number))
def memoization(n, Counter, dic):
if n in dic:
return dic[n]
else:
c.increment()
main()
this is what I have but I honestly don't know where to go from here, any help is greatly appreciated!
From what I can tell your Counter simply needs to be declared properly. This ensures that you pass the same instance of the Counter class along to the method.
def main():
...
my_counter_name = Counter() # <-- NAME THIS
memoization(n, my_counter_name, dic) # <-- pass the same name
And change this:
def memoization(n, Counter, dic): # <-- No need to write the class in Python
# just the local name for the variable
if n in dic:
return dic[n]
else:
c.increment()
If you would like to use c as the name for the counter as you have indicated in line 4 of the memoization method, you should change the input variable to this:
def memoization(n, c, dic):
if n in dic:
return dic[n]
else:
c.increment()
Hopefully that helps.
Related
My __repr__ method works fine using objects created in it's class, but with objects that were created with the help of importing a library and using methods from it, it only represented the memory address...
from roster import student_roster #I only got the list if students from here
import itertools as it
class ClassroomOrganizer:
def __init__(self):
self.sorted_names = self._sort_alphabetically(student_roster)
def __repr__(self):
return f'{self.get_combinations(2)}'
def __iter__(self):
self.c = 0
return self
def __next__(self):
if self.c < len(self.sorted_names):
x = self.sorted_names[self.c]
self.c += 1
return x
else:
raise StopIteration
def _sort_alphabetically(self,students):
names = []
for student_info in students:
name = student_info['name']
names.append(name)
return sorted(`your text`names)
def get_students_with_subject(self, subject):
selected_students = []
for student in student_roster:
if student['favorite_subject'] == subject:
selected_students.append((student['name'], subject))
return selected_students
def get_combinations(self, r):
return it.combinations(self.sorted_names, r)
a = ClassroomOrganizer()
# for i in a:
# print(i)
print(repr(a))
I tried displaying objects that don't rely on anther library, and they dispayed properly.
The issue I was facing was linked to me not understanding the nature of the object. itertools.combinations is an iterable, and in order to represent the values stored I needed to either:
unpack it inside a variable like:
def get_combinations(self, r):
*res, = it.combinations(self.sorted_names, r)
return res
Iter through it inside a loop and leave the original code intact like
for i in a.get_combinations(2):
print(i)
I prefer the second solution
Again, I am new to python. I need a FIFO with a limited depth.
F.e the depth is 5000, so after 5000 and more added items the first one's should be deleted to keep its depth is 5000. Some times I need to read 'the first' one and sometimes read the 'last one'. If I read the first one then it should be removed.
# class
class DictionaryDeque:
from collections import OrderedDict
def __init__(self, dequeDict=10):
self._stack = OrderedDict()
self._range = dictRange
self.setRange(dictRange)
self._len = 0
def len(self):
self._len = len(self._stack)
return self._len
def getRange(self):
return self._range
def setRange(self, range):
self._range = range
# change the dict range if the dict has more items
self.do_pop()
def add(self, key, value):
self._stack[key] = value
self.len()
self.do_pop()
def stack(self):
if self._len > 0:
self.do_pop()
return self._stack
else:
return ""
def last(self):
self.do_pop()
if self._len > 0:
return list(self._stack)[-1]
else:
return list(self._stack)[0]
def first(self):
self.do_pop()
return list(self._stack)[0]
def do_pop(self):
while self.len() > self._range:
self._stack.popitem(last=False)
self.len()
# end of class
dequeDict = DictionaryDeque(30)
for i in range (0, 40):
now = str(datetime.datetime.now())
dequeDict.add(now, i)
dequeDict.setRange(10)
print(dequeDict.len())
print(dequeDict.last())
print(dequeDict.first())
print(dequeDict.stack())
I have to implement the 'first read and remove' and some more functions, but before I start with that, I would love to know if this the/a way to go, or should there be something better?
Is there a way to avoid the list part in
list(self._stack)[0]
?
BTW, what is a good name for this class? < class name changed
Thank you
As a new python learner, I really appreciate your advice why my understanding about the following case is wrong:
When I wrote code as follows:
class Solution(object):
def isHappy(self, n):
seen = {}
while n!=1 and n not in seen.keys():
seen[n] = '*'
n = self.get_next(n)
return n==1
total_sum = 0
def get_next(self,no):
while no>0:
no,v = divmod(no,10)
total_sum+=v**2
return total_sum
test55 = Solution()
test55.isHappy(56)
But it throws me the error saying "local variable 'total_sum' referenced before assignment", I think it should work because: although we didn't initialize total_sum inside get_next function, I expect it should look for total_sum outside of the function. Could anyone share some advice why I'm wrong?
If we put total_sum inside get_next function, then it works:
class Solution(object):
def isHappy(self, n):
seen = {}
while n!=1 and n not in seen.keys():
seen[n] = '*'
n = self.get_next(n)
return n==1
def get_next(self,no):
total_sum = 0
while no>0:
no,v = divmod(no,10)
total_sum+=v**2
return total_sum
test55 = Solution()
test55.isHappy(56)
I wrote a generator function that I instantiate then call over and over again, each time this increments the number.
def pagecnt():
n = 1
while True:
yield n
n += 1
pg = pagecnt()
print(next(pg))
print(next(pg))
print(next(pg))
This prints 1, 2 and then 3. Is there some way to combine the generator and instantiation into a new function so that I can just call
print(newfunc())
print(newfunc())
print(newfunc())
to get 1, 2 and 3?
EDIT: I don't just want to call it only 3 times. It's used to generate page number. So I don't know in advance how many times I am going to call it. And between each call, there's lots of code to calculate stuff and generate graphs.
Just create a function which instantiates your generator and calls next n times
def combine_func(n):
pg = pagecnt()
for _ in range(n):
print(next(pg))
Or we can define a wrapper function which takes in the generator instance, and returns a function which we can call to get the next element
def combine_func(pg):
def next_elem():
return next(pg)
return next_elem
pg = pagecnt()
cf = combine_func(pg)
print(cf())
print(cf())
print(cf())
You could make a simple Counter class with __call__() defined:
class Counter():
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
c = Counter()
print(c())
print(c())
print(c())
prints:
1
2
3
You could also capture the iterator in a closure and return a lambda function:
from itertools import count
def Counter():
it = count(1)
return lambda: next(it)
c = Counter()
print(c())
print(c())
print(c())
prints the same as above. In both cases it would be easy to pass in a start value if you wanted to begin somewhere other than 0.
Edit:
This is the same as using count but with your custom generator:
def Counter():
def pagecnt():
n = 1
while True:
yield n
n += 1
it = pagecnt()
return lambda: next(it)
c = Counter()
print(c())
print(c())
print(c())
I have implemented fibonacci series using recursion:
def fibonacci(n):
if n==0:
return 0
elif n==1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)
I have also implemented it using dynamic programming:
def fibonacci(n):
result = [0, 1]
if n > 1:
for i in range(2, n+1):
result.append(result[i-1] + result[i-2])
return result[n]
I want to implement it using greedy approach. I am unable to think of it in greedy terms. Please provide a greedy approach for this problem.
I didn't understand what you wanted to say by saying the word 'greedy'. But these are ways:
Example 1: Using looping technique
def fib(n):
a,b = 1,1
for i in range(n-1):
a,b = b,a+b
return a
print fib(5)
Example 2: Using recursion
def fibR(n):
if n==1 or n==2:
return 1
return fibR(n-1)+fibR(n-2)
print fibR(5)
Example 3: Using generators
a,b = 0,1
def fibI():
global a,b
while True:
a,b = b, a+b
yield a
f=fibI()
f.next()
f.next()
f.next()
f.next()
print f.next()
Example 4: Using memoization
def memoize(fn, arg):
memo = {}
if arg not in memo:
memo[arg] = fn(arg)
return memo[arg]
fib() as written in example 1.
fibm = memoize(fib,5)
print fibm
Example 5: Using memoization as the decorator
class Memoize:
def __init__(self, fn):
self.fn = fn
self.memo = {}
def __call__(self, arg):
if arg not in self.memo:
self.memo[arg] = self.fn(arg)
return self.memo[arg]
#Memoize
def fib(n):
a,b = 1,1
for i in range(n-1):
a,b = b,a+b
return a
print fib(5)