Python - Accesing a list from another class method - python

I have a little problem with two different classes and two methods from the same class. I have a class B which is using both methods from class a which seems to work fine.
The problem however is that the first method from class a (insert) changes a list which the second method (lookup) from this class should use. It is using the global list which is still initiated with only zeroes. So I have no idea how to tell the method to use the HashMap from the insert method :/ I Hope somebody can help, thank you!
""" PUBLIC MEMBERS
Insert the given key (given as a string) with the given value (given as
an integer). If the hash table already contains an entry for the given key,
update the value of this entry with the given value.
"""
class Map:
global m
m = 10000
global HashMap
HashMap = []
for i in range(m):
HashMap.append(0)
#classmethod
def insert(self, key, value):
"""
>>> Map.insert("hi", 9)
[4,53]
"""
self.key = key
self.value = value
asci = 0
for i in key:
asci += ord(i)
hashindex = (asci%m)*2
print(hashindex)
print(HashMap[hashindex])
if HashMap[hashindex] == key:
HashMap[hashindex + 1] = value
else:
while HashMap[hashindex] != 0:
hashindex = ((asci+1)%m)*2
HashMap[hashindex] = key
HashMap[hashindex+1] = value
""" Check if there exists an entry with the given key in the hash table.
If such an entry exists, return its associated integer value.
Otherwise return -1.
"""
#classmethod
def lookup(self, key):
self.key = key
ascilookup = 0
for i in key:
ascilookup += ord(i)
indexlookup = (ascilookup%m)*2
for j in HashMap:
if HashMap[j]==key:
return HashMap[j + 1]
elif HashMap[j]==0:
return "-1"
else:
j =((j+1)%m)*2
if __name__ == "__main__":
import doctest
doctest.testmod()

This is a far simpler implementation of a map in python:
class Map:
HashMap = {}
def __init__(self,leng):
for i in range(leng):
self.HashMap[str(i)]=0
def insert(self, key, value):
self.HashMap[key]=value
def lookup(self, key):
for each in self.HashMap.iterkeys():
if each == key:
return self.HashMap[each]
return None
EDIT without using a dictionary, using two lists is easier:
class Map:
keys = []
values = []
def __init__(self,leng):
for i in range(leng):
self.keys.append(str(i))
self.values.append(0)
#classmethod
def insert(self, key, value):
self.keys.append(key)
self.values.append(value)
#classmethod
def lookup(self, key):
for x in range(0, len(self.keys)):
if self.keys[x] == key:
return self.values[x]
return None

Related

Why is my helper method not activating recursively?

I have a Binary Search Tree and I am trying to trace recursively in order through the tree and append each key,value to a list. It is only appending the first key,value to the list and not going through the list in order. I pasted my code below, along with the test code I used at the bottom. Any help on how to get past this issue is super appreciated!
class TreeMap:
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.left = None
self.right = None
def __init__(self):
self.root = None
self.numsearches = 0
self.numcomparisons = 0
def add(self, newkey, newvalue):
newkey = newkey.lower()
if self.root == None:
self.root = TreeMap.Node(newkey, newvalue)
else:
TreeMap.add_helper(self.root, newkey, newvalue)
def add_helper(thisnode, newkey, newvalue):
if newkey <= thisnode.key:
if thisnode.left == None:
thisnode.left = TreeMap.Node(newkey, newvalue)
else:
TreeMap.add_helper(thisnode.left, newkey, newvalue)
else:
if thisnode.right == None:
thisnode.right = TreeMap.Node(newkey, newvalue)
else:
TreeMap.add_helper(thisnode.right, newkey, newvalue)
def print(self):
TreeMap.print_helper(self.root, 0)
def print_helper(somenode, indentlevel):
if somenode == None:
print(" "*(indentlevel),"---")
return
if not TreeMap.isleaf(somenode):
TreeMap.print_helper(somenode.right, indentlevel + 5)
print(" "*indentlevel + str(somenode.key) + ": " +str(somenode.value))
if not TreeMap.isleaf(somenode):
TreeMap.print_helper(somenode.left, indentlevel + 5)
def isleaf(anode):
return anode.left == None and anode.right == None
def listify(self, whichorder="in"):
'''
Returns a list consisting of all the payloads of the tree. (This returns a plain old Python List.)
The order of the payloads is determined by whichorder, which defaults to inorder.
The other possibilities are "pre" and "post".
If the tree is empty, return the empty list.
'''
assert type(whichorder) is str,"Whichorder is a string, and can only be pre, in or post"
assert whichorder in ["pre","in","post"],"Whichorder is a string, and can only be pre, in or post"
return TreeMap.listify_helper(self.root, whichorder)
def listify_helper(somenode, whichorder):
order_list = []
if somenode == None:
return order_list
elif somenode != None and whichorder == 'in':
TreeMap.listify_helper(somenode.left, 'in')
order_list.append(somenode.key+ '='+somenode.value)
TreeMap.listify_helper(somenode.right, 'in')
return order_list
TEST CODE:
import treemap
translator = treemap.TreeMap()
translator.add("cat", "Katze")
translator.add("bird", "Vogel")
translator.add("dog", "Hund")
translator.add("snake", "IDK")
translator.add("bear", "IDK")
translator.add("octopus", "Tintenfisch")
translator.add("horse", "Pferd")
translator.add("zebra", "IDK")
translator.print()
print("---------------------------------------------------")
print (translator.listify())
The problem is here:
def listify_helper(somenode, whichorder):
order_list = []
This function initialises its own local order_list every time it is invoked. Pass order_list as a parameter instead so that the same list is appended to by each recursive invocation.
Alternatively, append each element of the result of the recursive calls of listify_helper to order_list, although this approach could result in unneeded copying.

Python dictionary not adding subsequent keys after the first

Fairly new to Python and I can not figure this out. I go to add a key to a dictionary and it adds it fine. I can even update that same key with a new value, however when I go to add a second key to the dictionary, it does not add the second key value pair.
class CountedSet:
def __init__(self):
self.data = {}
def __iadd__(self,other):
if isinstance(other,int):
self.data[other] = self.data.get(other, 0) + 1
return self
elif isinstance(other,CountedSet):
#TODO::iterate through second countedSet and update self
return self
def __add__(self,obj):
for key, value in obj.data.items():
if len(self.data) == 0:
self.data[key] = value
elif self.data[key]:
self.data[key] = self.data[key] + value
else:
self.data[key] = value
return self
def __getitem__(self,item):
if item in self.data:
return self.data.get(item)
else:
return None
def __str__(self):
for key, value in self.data.items():
return("{%s,%s}" % (key,value))
a = CountedSet()
a += 17
a += 4
print(a)
This simply outputs {17,1} when I would expect to see {17,1} {4,1}
Your __str__ implementation returns on the first iteration of the for-loop:
def __str__(self):
for key, value in self.data.items():
return("{%s,%s}" % (key,value)) # here
Maybe you want something like:
def __str__(self):
return " ".join([{"{%s,%s}" % (k,v) for k, v in self.data.items()])
Or, without the comprehension:
def __str__(self):
items = []
for key, value in self.data.items():
items.append("{%s,%s}" % (key,value))
return ' '.join(items)

Python MyHashTable class: search method with linear probing

I need help implementing a method for my "MyHashTable" class:
def search(self, search_key):
The method is supposed to use linear probing to handle collision resolution. If the search_key is in the hash table then the method returns the slot number of the slot containing that search_key. If the search_key is not in the hash table, the method returns -1
My class looks like this:
class MyHashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = [None] * self.capacity
def __str__(self):
return str(self.slots )
def __len__(self):
count = 0
for i in self.slots:
if i != None:
count += 1
return count
def hash_function(self, key):
i = key % self.capacity
return i
def insert(self, key):
slot = self.hash_function(key)
orig = slot
while True:
if self.slots[slot] is None:
self.slots[slot] = key
return slot
if self.slots[slot] == key:
return -2
slot = (slot + 1) % self.capacity
if slot == orig:
return -1
def search(self, search_key):
Any help or tutorial links would be awesome.
Thanks
You are only using a single list to store all the values, if you wanted a hash table you might use a list of lists where each list was a bucket but if you just want to check if the element is in your hash table with your own code:
def search(self, search_key):
hsh = self.hash_function(search_key)
if self.slots[hsh] is None:
return -1
while hsh < self.capacity:
if self.slots[hsh] == search_key:
return hsh
hsh += 1
return -1
You also have to handle the case where you have multiple collisions so we need at worst to check every element in the hash table to find the correct value:
def search(self, search_key):
hsh = self.hash_function(search_key)
if self.slots[hsh] is None:
return -1
for i in range(self.capacity):
mod = (hsh + i) % self.capacity
if self.slots[mod] == search_key:
return mod
return -1
The first while loop will probe one value over at a time but if we have wrapped around the list from multiple collisions it would miss elements at the start so using range and mod = (hsh + i) % self.capacity makes sure we check all entries like the example below.
m = MyHashTable(5)
m.insert(13) # 13 % 5 = 3
m.insert(73) # 83 % 5 = 3
m.insert(93) # 93 & 5 = 3
print(m.search(13)) # 3
print(m.search(73)) # 4
print(m.search(93)) # 0
print(m.search(2)) # -1
You can make your len method O(1) by keeping track of when you add a unique value to your hash table, there is also a nice wiki page on Open_addressing parts of which you can adopt into your code and it will help you create a proper mapping of keys to values and resized your hash table when needed. If you want to store more than just numbers you need to use a different hash function, I just use hash but you can use whatever you like. Also using in when your hash table is full and the key does not exist will cause an infinite loop so you will need to handle that case:
class MyHashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = [None] * self.capacity
self.count = 0
def __str__(self):
return str(self.slots)
def __contains__(self, item):
return self.search(item) != -1
def __len__(self):
return self.count
def hash_function(self, key):
return hash(key) % self.capacity
def find_slot(self, key):
slot = self.hash_function(key)
while self.slots[slot] is not None and self.slots[slot] != key:
slot = (slot + 1) % self.capacity
return slot
def insert(self, key):
slot = self.find_slot(key)
if self.slots[slot] != key:
self.slots[slot] = key
self.count += 1
def search(self, key):
i = self.find_slot(key)
if self.slots[i] is not None:
return i
return -1
Add a __contains__ will also allow you to use in to test for membership:
m = MyHashTable(5)
m.insert("foo")
m.insert(73)
m.insert(93)
m.insert(1)
print(m.search(73))
print(m.search(93))
print(m.search(1))
print(m.search("foo"))
m.insert(73)
print(m.slots)
print(len(m))
print("foo" in m)
print(5 in m)
Output:
3
4
1
0
['foo', 1, None, 73, 93]
4
True
False

Python Hashing with lists

I need some help making a insert function that adds values into a hash table where each table position is a list. If there is collision the value just gets added to the list at the right position.
class MyChainHashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = []
for i in range(self.capacity):
self.slots.append([])
def __str__(self):
info = ""
for items in self.slots:
info += str(items)
return info
def __len__(self):
count = 0
for i in self.slots:
count += len(i)
return count
def hash_function(self, key):
i = key % self.capacity
return i
def insert(self, key):
#need help
#this should insert each value into seperate lists, and if there is collision
#it should add the value to make a list with +1 positions.
#eg. [26][][54, 93][][17, 43][31][][][][][][][77, 90]
def insert(self, key):
self.slots[self.hash_function(key)].append(key)
You can just use a dictionary for this:
def insertWithChain(dict, key, value):
if key in d:
d[key].append(value) # add value to an existing list
else:
d[key] = [value] # new value in a new list by itself

Why does overriding __contains__ break OrderedDict.keys?

I'm subclasssing OrderedDict (Cpython, 2.7.3) to represent a datafile. __getitem__ pulls a field out of the datafile and sets it on the current instance similar to the code I've posted below. now I would like to override __contains__ to return True if the field is in the dictionary or in the file on the disk since it can be read either way. However, this seems to break OrderedDict's ability to inspect it's keys.
from collections import OrderedDict
dictclass = OrderedDict
class Foo(dictclass):
def __getitem__(self,key):
try:
return dictclass.__getitem__(self,key)
except KeyError:
pass
data = key*2
self[key] = data
return data
def __contains__(self,whatever):
return dictclass.__contains__(self,whatever) or 'bar' in whatever
a = Foo()
print a['bar']
print a.keys()
If you run the code above, you'll get this output:
barbar
[]
Note that if you change dictclass = dict in the above code, it still seems to work (giving the following output).
barbar
['bar']
Am I doing something horribly wrong?
When Foo.__contains__ is not defined:
a['bar']
calls Foo.__getitem__, which executes
self[key] = data
This calls OrderedDict.__setitem__, which is defined this way:
def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
last = root[PREV]
last[NEXT] = root[PREV] = self.__map[key] = [last, root, key]
dict_setitem(self, key, value)
Since Foo.__contains__ is not defined,
if key not in self:
is True. So the key is properly added to self.__root and self.__map.
When Foo.__contains__ is defined,
if key not in self:
if False. So the key is not properly added to self.__root and self.__map.
Foo.__contains__ effective fools OrderedDict.__setitem__ into thinking that the 'bar' key has already been added.
I found it helpful to play with the following code (adding print statements in __setitem__ and __iter__):
from collections import OrderedDict
dictclass = OrderedDict
class Foo(dictclass):
def __getitem__(self,key):
try:
return dictclass.__getitem__(self,key)
except KeyError:
pass
data = key*2
self[key] = data
return data
def __contains__(self,whatever):
print('contains: {}'.format(whatever))
return dictclass.__contains__(self,whatever) or 'bar' in whatever
def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
print('key not in self: {}'.format(key not in self))
if key not in self:
root = self._OrderedDict__root
last = root[PREV]
last[NEXT] = root[PREV] = self._OrderedDict__map[key] = [last, root, key]
dict_setitem(self, key, value)
def __iter__(self):
'od.__iter__() <==> iter(od)'
# Traverse the linked list in order.
NEXT, KEY = 1, 2
root = self._OrderedDict__root
curr = root[NEXT]
print('curr: {}'.format(curr))
print('root: {}'.format(root))
print('curr is not root: {}'.format(curr is not root))
while curr is not root:
yield curr[KEY]
curr = curr[NEXT]
a = Foo()
print a['bar']
# barbar
print a.keys()
# ['bar']
Notice that you can avoid this problem by making Foo a subclass of collections.MutableMapping and delegating most of its behavior to a OrderedDict attribute:
import collections
dictclass = collections.OrderedDict
class Foo(collections.MutableMapping):
def __init__(self, *args, **kwargs):
self._data = dictclass(*args, **kwargs)
def __setitem__(self, key, value):
self._data[key] = value
def __delitem__(self, key):
del self._data[key]
def __iter__(self):
return iter(self._data)
def __len__(self):
return len(self._data)
def __getitem__(self,key):
try:
return self._data[key]
except KeyError:
pass
data = key*2
self[key] = data
return data
def __contains__(self,whatever):
return dictclass.__contains__(self,whatever) or 'bar' in whatever
which yields
a = Foo()
print a['bar']
# barbar
print a.keys()
# ['bar']
even with __contains__ defined.
What breaks your code is the or 'bar' in whatever. If you remove it, it will work as with the change dictclass = dict you mention.
The __setitem__ implementation of OrderedDict is this:
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link at the end of the linked list,
# and the inherited dictionary is updated with the new key/value pair.
if key not in self:
root = self.__root
last = root[0]
last[1] = root[0] = self.__map[key] = [last, root, key]
return dict_setitem(self, key, value)
So with self["bar"] = "barbar", the condition should be False, but it is True even before inserting any item. Thus, the key isn' added to self.__root which is used in OrderedDict.__iter__:
def __iter__(self):
'od.__iter__() <==> iter(od)'
# Traverse the linked list in order.
root = self.__root
curr = root[1] # start at the first node
while curr is not root:
yield curr[2] # yield the curr[KEY]
curr = curr[1] # move to next node
Since the code for retrieving the values uses this iterator and self.__root does not contain "bar", this concrete key cannot be returned in the values.

Categories