Trying to add an insert(self, key) method that inserts the key into the appropriate position while linear probing for resolving collisions.
My current code, I'm just not 100% sure how to inset the str into the hash table.
Testing code:
#Test
my_table = HashTable(5)
my_table.insert('hello')
print("Hashtable:", my_table)
result:
Hashtable: [None, None, None, None, 'hello']
class HashTable:
def __init__(self, capacity):
self.capacity = capacity
self.slots = [None] * self.capacity
def __str__(self):
return str(self.slots )
def is_empty(self):
return self.slots.count(None) == len(self.slots)
def hash(self, key):
sum = 0
for char in key:
sum += ord(char)
sum2 = "%04d" % (sum)
digits = int((sum2[2]) + (sum2[3]))
number = int(digits * digits)
return number % len(self.slots)
def insert(self, key):
count = 0
position = key%self.capacity
if self.slots[key%self.capacity] == None:
self.slots[key%self.capacity] = key
else:
while self.slots[position] != None:
position +=1
if position >= self.capacity:
position = 0
self.slots[position%self.capacity] = key
return self.slots
Im currently getting a Type error
>>>TypeError: not all arguments converted during string formatting line 25, in insert
position = key%self.capacity
I just need some advice on how to add the string into the hash table.
key ('hello') is a string object. You need to convert it to integer to do modulo. Otherwise it will perform printf-style string formatting; causes error because there's no % in the string:
position = key % self.capacity
Call self.hash to get hash value:
def insert(self, key):
position = self.hash(key) % self.capacity
if self.slots[position] == None:
self.slots[position] = key
else:
while self.slots[position] != None:
position += 1
if position >= self.capacity:
position = 0
self.slots[position%self.capacity] = key
return self.slots
UPDATE if body can be merged into else:
def insert(self, key):
position = self.hash(key) % self.capacity
while self.slots[position] != None:
position += 1
if position >= self.capacity:
position = 0
self.slots[position%self.capacity] = key
return self.slots
Related
In this assignment for my Python Data Structures course, I'm combining concepts of hash tables and linked lists to create a chained hash table. I'm struggling with setting the items in the chained hash table. I would appreciate any guidance and direction towards finding a solution. I will provide my code, output and error message below:
Python Code
class SLLH():
class DataNode():
def __init__(self, key, val):
if not isinstance(val,str) and not isinstance(val,int):
raise Exception("data must be either interger or string")
if not isinstance(key,str) and not isinstance(key,int):
raise Exception("key type must be either string or integer")
self.key = key
self.val = val
self.next = None
def __str__(self):
return str(self.key)+",|"+str(self.val)+"|"
def __init__(self):
self.head = None
self.sz = 0
def append(self, key, val):
node = self.DataNode(key,val)
node.next = self.head
self.head = node
self.sz += 1
def remove_at(self, idx):
if idx < 0:
raise Exception("index cannot be negative for chain LL.")
cur = self.head
cur_idx = 0
if(idx == 0 and self.head):
node = self.head
self.head = self.head.next
self.sz -=1
return str(node.val)
while(cur and cur_idx < idx -1):
cur = cur.next
cur_idx +=1
if(not cur or not cur.next):
raise Exception("Index out of bounds for chain LL.")
node = cur.next
cur.next = cur.next.next
self.sz -=1
return node
def remove(self, key):
to_be_removed = []
for i in range(self.sz):
if self.getitem_at(i).key==key:
to_be_removed.append(i)
break
if to_be_removed:
self.remove_at(to_be_removed[0])
else:
raise Exception(f"An entry with key {key} doesn't exist")
def getitem_at(self, idx):
cur = self.head
cur_idx = 0
while(cur and cur_idx < idx):
cur = cur.next
cur_idx+=1
if(cur):
return cur
raise Exception(f"Inedex {idx} out of bounds for list of length {cur_idx+1}")
def __getitem__(self, key):
curr = self.head
while curr.key != key:
curr = curr.next
return curr.val
def __str__(self):
str_rep = ""
arrow_str = "--> "
str_rep += arrow_str
cur = self.head
while(cur):
str_rep+=str(cur)+" "
str_rep += arrow_str
cur = cur.next
str_rep += "NULL\n"
return str_rep
class ChainedHashTable():
def to_ascii_sum(self, key_str):
return sum(list(map(ord, key_str)))
def sum_digits(self, key_int):
sum = 0
for digit in str(key_int):
sum += int(digit)
return sum
def data_to_int(self, key):
if (type(key)) == str:
return self.to_ascii_sum(key)
elif (type(key)==int):
return self.sum_digits(key)
else:
raise Exception("key type must be either string or integer")
def mod_hashFunc(self, key):
return self.data_to_int(key)%self.slot_count
def __init__(self, slot_count):
assert slot_count > 0, Exception("table size must be greater than zero")
self.slot_count = slot_count
self.table = [SLLH() for _ in range(self.slot_count)]
self.hashfunc = self.mod_hashFunc
def __getitem__(self, key):
slot_idx = self.hashfunc(key)
ll = self.table[slot_idx]
return ll[key]
def __setitem__(self, key, val):
slot_idx = self.hashfunc(key)
linkedList = self.table[slot_idx]
linkedList[key] = val
def remove(self, key):
slot_idx = self.hashfunc(key)
self.table[slot_idx].remove(key)
def __str__(self):
str_rep = ""
for slot in range(self.slot_count):
str_rep += str(self.table[slot])
return str_rep
Code For Testing
ht = ChainedHashTable(7)
print(ht)
ht[0] = 10
ht[5] = 50
ht[9] = 90
ht[4] = 40
print(ht)
Output and TypeError
--> NULL
--> NULL
--> NULL
--> NULL
--> NULL
--> NULL
--> NULL
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Input In [3], in <cell line: 1>()
----> 1 ht[0] = 10
2 ht[5] = 50
3 ht[9] = 90
Input In [1], in ChainedHashTable.__setitem__(self, key, val)
144 slot_idx = self.hashfunc(key)
145 linkedList = self.table[slot_idx]
--> 146 linkedList[key].append(key,value)
Input In [1], in SLLH.__getitem__(self, key)
83 def __getitem__(self, key):
85 curr = self.head
---> 87 while curr.key != key:
88 curr = curr.next
90 return curr.val
AttributeError: 'NoneType' object has no attribute 'key'
As stated in comments, an implementation of sum_digits was missing which you have now added.
In the new error trace we see this code:
linkedList = self.table[slot_idx]
linkedList[key].append(key,value)
In the actual code you presented, this code looks different:
linkedList = self.table[slot_idx]
linkedList[key] = value
Either way, it is wrong. linkedlist is just that: a linked list. You cannot access linkedlist[key]. You should just do:
linkedList = self.table[slot_idx]
linkedList.append(key,value)
With that change the main code will run without error.
I am just experimenting with a hybrid model of Linked List with some modifications. I have already implemented object.delete_node(index) which just link the next node as it is in vanilla Linked Lists. Now, and want to implement del object[index] which does the same function as object.delete_node(index). How could I implement it? It is implemented in list and dict in Python. Which method is responsible for the same?
Below is the code for my LinkedList which works pretty well.
class Node:
def __init__(self, data = None, next_pointer = None):
self.data = data
self.next_pointer = next_pointer
def __str__(self):
return self.__repr__()
def __repr__(self):
return str(self.data)
class LinkedList:
def __init__(self):
self.head = Node()
self.length = 0
def insert_node(self, data):
new_node = Node(data) # node to be inserted
current_node = self.head
while current_node.next_pointer != None: # it'll only stop at the last node which is obviously empty
current_node = current_node.next_pointer # bring out next pointer
current_node.next_pointer = new_node
self.length += 1
def delete_node(self, index):
if self.length == 0: raise ValueError(f"Can not delete from empty Linked List")
if (index > self.length - 1) or (index < -self.length -1): raise ValueError(f"index {index} out of bounds of max length")
if index < 0: index = self.length + index
count = 0
current_node = self.head
while count < index:
current_node = current_node.next_pointer
count += 1
current_node.next_pointer = current_node.next_pointer.next_pointer if current_node.next_pointer.next_pointer != None else None
self.length -= 1
def _slice_return(self, slice_index):
'''
Implement slicing Operation just like in Python Lists and Strings
'''
index = slice_index.start
stop = min(slice_index.stop, self.length -1)
step = 1 if slice_index.step == None else slice_index.step
if index < 0: raise NotImplementedError("Negative slicing not implemented")
if (index > self.length - 1) or (index < -self.length -1): raise ValueError(f"index {index} out of bounds of max length")
if index < 0: index = self.length + index
ll = LinkedList()
for i in range(index, stop,step):
ll.insert_node(self[i].data)
return ll
def __getitem__(self, index):
if isinstance(index, slice):
return self._slice_return(index)
if (index > self.length - 1) or (index < -self.length -1): raise ValueError(f"index {index} out of bounds of max length")
if index < 0: index = self.length + index
count = 0
current_node = self.head.next_pointer
while count != index:
current_node = current_node.next_pointer
count += 1
return current_node
def __len__(self):
return self.length
def __str__(self):
array = []
node = self.head
count = self.length
while count > 0:
node = node.next_pointer
array.append(node.data)
count -= 1
return(str(array))
def __repr__(self):
return self.__str__()
ll = LinkedList()
ll.insert_node("a")
ll.insert_node("b")
ll.insert_node("A")
ll.insert_node("B")
ll.delete_node(2) # delete 3rd node
Answer based on #jonrsharpe comment:
There is a Datamodel section in python docs with list of available dunder methods
In your case its:
object.__delitem__(self, key)
Called to implement deletion of self[key]. Same note as for __getitem__(). This should only be implemented for mappings if the objects support removal of keys, or for sequences if elements can be removed from the sequence. The same exceptions should be raised for improper key values as for the __getitem__() method.
What I am trying to do
I have this hashtable which I am trying to double hash the value however i am getting the error
if hashtable_list[hashKey] == None:
IndexError: list index out of range
I have been at this for hours and can't seem to find where I am going wrong with this double hashing algorithm. Please can someone help me . Any help will be much appreciated from the bottom of my heart
# The HashParent class is the main class and follows an ADT
# in which it holds the key and value
class HashParent:
def __init__(self, key, value):
self.key = key
self.value = value
self.isItemDeleted = False
class HashTable(object):
"""
a basic, minimal implementation of a hash map
"""
def __init__(self):
"""
constructs a new Map
"""
#Create a table size of 4 None values eg [None, None, None, None]
self.table = [None] * 4
self.hashTableSize = 0
#Uses Linear Probing to hash values into the table
def __get_hash_code(self, key, value):
return (hash(key) + value) % len(self.table)
# Uses Linear Probing to hash values into the table
def hashUsingQudratic(self, key, value):
return (hash(key) + value ** 2) % len(self.table)
def double_hashing(self, key, value):
hashtable_size = self.hashTableSize
hashtable_list = self.table
hashKey = hash(key)
if hashtable_list[hashKey] == None:
hashtable_list[hashKey] = key
else:
new_hashkey = hashKey
while hashtable_list[new_hashkey] is not None:
steps = value - (key % value)
new_hashkey = (new_hashkey + steps) % hashtable_size
hashtable_list[new_hashkey] = key
return hashtable_list
def getitem(self, key):
"""
gets the value associated with the key
"""
hashTableLength = len(self.table)
for i in range(hashTableLength):
index = self.__get_hash_code(key, i)
if self.table[index] != None:
if self.table[index].key == key:
if self.table[index].isItemDeleted:
raise KeyError('Key is not in the map')
else:
return self.table[index].value
elif self.table[index] is None:
raise KeyError('Key is not in the map')
raise KeyError('Hmm something has gone wrong here')
def whichMethod(self, whichType, key,i):
if whichType == 'linear':
index = self.__get_hash_code(key, i)
return index
if whichType == 'quadratic':
index = self.hashUsingQudratic(key, i)
return index
if whichType == 'double':
index = self.double_hashing(key, i)
return index
def putItem(self, key, item, whichType):
"""
stores the key value combo in the table
implements open addressing collision resolution
"""
parent = HashParent(key, item)
for i in range(len(self.table)):
index = self.whichMethod(whichType,key,i)
if self.table[index] is None or self.table[index].isItemDeleted:
self.table[index] = parent
self.hashTableSize += 1
break
def deleteValue(self, key):
"""
deletes a value from the hash table
"""
hashTableLength = len(self.table)
for i in range(hashTableLength):
index = self.__get_hash_code(key, i)
if self.table[index] != None:
if self.table[index].key == key:
if self.table[index].isItemDeleted:
raise KeyError('Key is not in the map')
else:
self.table[index].isItemDeleted = True
self.hashTableSize -= 1
break
m = HashTable()
linear = 'linear'
quadratic = 'quadratic'
doubleHash = 'double'
m.putItem('first', 1,doubleHash)
m.putItem('ninth',9 ,doubleHash)
m.putItem('third', 3,doubleHash)
m.putItem('Tenth', 10,doubleHash)
print("The value at key 'ninth' is:" ,m.getitem('ninth'))
m.deleteValue('Tenth')
#Size should now be 3
print('The Hashatble size is:',m.hashTableSize)
Ok, so you do m.putItem('first', 1, doubleHash), so key is "first".
You pass key from putItem to whichMethod, then from whichMethod to double_hashing.
Then, double_hashing does this:
hashtable_list = self.table
self.table starts out as self.table = [None] * 4. It just has four Nones. So hashtable_list will be [None, None, None, None].
Then, it does:
hashKey = hash(key)
if hashtable_list[hashKey] == None:
hash returns an integer, and key is "first". Let's just try that in the interpreter:
>>> hash("first")
-4954399314613441385
>>>
So, hashtable_list[hashKey] is like saying [None, None, None, None][hash("first")], which is like saying [None, None, None, None][-4954399314613441385]. There's your IndexError.
I have this assignment where I would like to create an empty string where sparse vector data would be stored at. I need to check whether the key index exists in the sparse vector (self.data). If not, I need to store, in the empty string, the sparse vector and zero values. The error I am getting is TypeError: str returned non-string (type NoneType). This is my code:
class SparceVector(object):
def __init__(self, n):
self.length = n
self.data = {}
def __str__(self):
outstr = None or ""
assert 0 <= key and key < self.length
try:
outstr = ((str(key), str(value)) for key,value in self.data.items())
return
except KeyError:
return 0
return "The sparce vector is {}".format(outstr)
def __len__(self):
return self.legth
def __getitem__(self, key):
assert 0 <= key and key < self.length
try:
return self.data[key]
except KeyError:
return 0
return self.data[key]
def __setitem__(self, key, value):
assert 0 <= key and key < self.length
if value != 0:
self.data[key] = value
def nonzeros(self):
return self.data
def __add__(self, other):
assert self.length == other.length
merged = SparceVector(self.length)
c = {key:value for key, value in self.data.items()}
for key, value in other.data.items():
try:
c[key] += value
except KeyError:
c[key] = value
merged.data = c
merged.nonzeros()
return merged
def __iter__(self):
return iter(self.data)
def key(self):
return self.data.key()
def items(self):
return self.data.items()
def values(self):
return self.data.values()
I am implementing a Hashmap in python. Right now, I am manually inserting the key and value. What I want is to automatically assign the key of the given value in ascending order. Suppose, we have a number n=8 , then it will automatically start assigning key starts from 1 to 8 , when it reach the key number 8 and we want to insert more values, then it will show a print message like, entry is full.
Instead of
hm.put("1", "sachin")
I want ,
hm.put("sachin")
and it should automatically assign key 1 for sachin.
class Node:
def __init__(self, key, value):
self.key = key
self.value = value
self.next = None
class HashMap:
def __init__(self):
self.store = [None for _ in range(16)]
def get(self, key):
index = hash(key) & 15
if self.store[index] is None:
return None
n = self.store[index]
while True:
if n.key == key:
return n.value
else:
if n.next:
n = n.next
else:
return None
def put(self, key, value):
nd = Node(key, value)
index = hash(key) & 15
n = self.store[index]
if n is None:
self.store[index] = nd
else:
if n.key == key:
n.value = value
else:
while n.next:
if n.key == key:
n.value = value
return
else:
n = n.next
n.next = nd
hm = HashMap()
hm.put("1", "sachin")
hm.put("2", "sehwag")
hm.put("3", "ganguly")
hm.put("4", "srinath")
hm.put("5", "kumble")
hm.put("6", "dhoni")
hm.put("7", "kohli")
hm.put("8", "pandya")
hm.put("9", "rohit")
hm.put("10", "dhawan")
hm.put("11", "shastri")
hm.put("12", "manjarekar")
hm.put("13", "gupta")
hm.put("14", "agarkar")
hm.put("15", "nehra")
hm.put("16", "gawaskar")
hm.put("17", "vengsarkar")
print(hm.get("1"))
print(hm.get("2"))
print(hm.get("3"))
print(hm.get("4"))
print(hm.get("5"))
print(hm.get("6"))
print(hm.get("7"))
print(hm.get("8"))
print(hm.get("9"))
print(hm.get("10"))
print(hm.get("11"))
print(hm.get("12"))
print(hm.get("13"))
print(hm.get("14"))
print(hm.get("15"))
print(hm.get("16"))
print(hm.get("17"))