Python: Implementing a Map with Chaining - python

My assignment is to implement a map with chaining by creating a hash table with two lists, one called "slots" and one called "data. My code seems to work until the 'G' character. I can't quite pinpoint what is going on here and I have tried debugging.
class HashTable:
def __init__(self):
self.size = 11
self.slots = [None] * self.size
self.data = [None] * self.size
def put(self,key,data):
hashvalue = self.hashfunction(key,len(self.slots))
if self.slots[hashvalue] == None:
self.slots[hashvalue] = list()
self.slots[hashvalue].append(key)
self.data[hashvalue] = list()
self.data[hashvalue].append(data)
else:
if self.slots[hashvalue] != None:
self.data[hashvalue].append(data) #replace
def hashfunction(self,key,size):
return key%size
def get(self,key):
startslot = self.hashfunction(key,len(self.slots))
data = None
stop = False
found = False
position = startslot
while self.slots[position] != None and not found and not stop:
for index in range (len(self.slots[position])):
if self.slots[position][index]== key:
found = True
data = self.data[position][index]
break
position+1
if position == startslot:
stop = True
return data
def __getitem__(self,key):
return self.get(key)
def __setitem__(self,key,data):
self.put(key,data)
## TEST FOR HashTable
h = HashTable() # create new hash table
nums = [1, 3, 5, 50, 1000] # some keys
nums = nums + [ len(h.slots)*i for i in range(20)] # some keys that have same hash
vals = [ chr(x) for x in range(ord('A'),ord('Z')) ] # list of single letters from A to Z
# add key/values
for i in range(len(nums)):
# print("adding (%d, %s)"%(nums[i],vals[i]),end=" ")
h[nums[i]] = vals[i]
for i in range(len(nums)):
key = nums[i]
value = vals[i]
gotValue = h[key]
assert gotValue == value,"expected key: %d to lookup value: %s but got value %s instead " % (key, value, gotValue)
print("\nAll TESTS PASSED")

I found my issue:
I forgot to add a line under:
if self.slots[hashvalue] != None:
that adds the key to the [hashvalue] of slots.
So now I have:
if self.slots[hashvalue] != None:
self.slots[hashvalue].append(key)
self.data[hashvalue].append(data)
It was adding the data value to the corresponding list "data", but not the matching key value to the list "slots"

Related

CSP Recursive Calls Fail with with Range(a,b) but not Explicit Range

Sudoku is a well known CSP and, in this case, LC problem. I don't need the solution, which follows.
My question is why does self.DOMAIN = "123456789" (line #4) work, whereas self.DOMAIN = map(str, range(1, 10)) (line #5) does not? Are they not equivalent?
class Solution:
def __init__(self):
self.SIZE = 9
# self.DOMAIN = map(str, range(1, self.SIZE + 1)) # THIS DES NOT WORK NOT WORK
self.DOMAIN = "123456789" # THIS WORKS
self.EMPTY = "."
from collections import defaultdict
self.rows = defaultdict(set) # {row:set}
self.cols = defaultdict(set) # {col:set}
self.boxs = defaultdict(set) # {box:set}
self.row_idx = lambda cell: cell // self.SIZE # determines row from cell num
self.col_idx = lambda cell: cell % self.SIZE # determins col from cell num
self.box_idx = lambda r, c: (r // 3) * 3 + c // 3 # determines box from row, col
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
assert(len(board) == self.SIZE and len(board[0]) == self.SIZE), \
"Sudoku board must be 9x9 in dimensions"
# Initialize board state
self.board = board
for r in range(self.SIZE):
for c in range(self.SIZE):
val = self.board[r][c]
if val != self.EMPTY:
self.rows[r].add(val)
self.cols[c].add(val)
self.boxs[self.box_idx(r, c)].add(val)
# Begin backtracking search from the first cell
self.backtrack(0)
def backtrack(self, cell):
if cell == 81:
# all values have been set and we are outside the board range
return True
r, c = self.row_idx(cell), self.col_idx(cell)
if self.board[r][c] != self.EMPTY:
# nothing to do, continue search
return self.backtrack(cell + 1)
# explore values in the domain for this cell
for candidate_val in self.DOMAIN:
if self.is_valid(r, c, candidate_val):
# place candidate
self.board[r][c] = candidate_val
self.rows[r].add(candidate_val)
self.cols[c].add(candidate_val)
self.boxs[self.box_idx(r, c)].add(candidate_val)
# continue search
if self.backtrack(cell + 1):
return True
# remove candidate and backtrack
self.board[r][c] = self.EMPTY
self.rows[r].remove(candidate_val)
self.cols[c].remove(candidate_val)
self.boxs[self.box_idx(r, c)].remove(candidate_val)
# no solution found for all values in the domain for this cell
return False
def is_valid(self, r, c, val):
""" Returns whether a value can be placed in board[r][c] in the current game state """
if val in self.rows[r]:
return False
if val in self.cols[c]:
return False
if val in self.boxs[self.box_idx(r, c)]:
return False
return True
You are suffering confusion between "generator" and "container".
Consult type( ... ) to tell the difference between them.
Python generators are "lazy", for excellent technical reasons.
Sometimes we can get away with just evaluating
the first K items of an infinite generator.
In your method you want everything greedily pulled out,
and then stored in a container.
The conventional way to phrase this is to wrap map with list:
self.DOMAIN = list(map(str, range(1, 10)))
or perhaps in your case you would prefer that .join pull them out:
self.DOMAIN = ''.join(map(str, range(1, 10)))

I'm having difficulty speeding up my HashMap

I'm given a .txt file with a total of 1 million songs and their respective authors. My given task is to write a HashMap in python which can store this information using either the Author or the Song as a key. I've written a HashMap that works but is running incredibly slow, taking up to 2 minutes to finish. (Expected time is apparently a few seconds at most, according to my tutor)
For collision handling I decided to use linked lists as from what I've gathered it's an effective way to handle collisions without drastically reducing performance.
from HashNode import HashNode
class HashTabell:
def __init__(self, size):
self.size = size
self.dict = {}
self.krock = 0
def store(self, nyckel, data):
hashval = self.__hash(nyckel)
## Shit is empty
if self.dict.get(hashval) != None:
get_val = self.dict[hashval]
## Is list, append normally
if isinstance(get_val, list):
list2 = self.dict[hashval]
found = False
for (k, val) in enumerate(list2):
if val.get_nyckel == nyckel:
list[k] = HashNode(nyckel, data) ## Update old value
found = True
break
if found:
self.dict[hashval] = list2
else:
self.dict[hashval] = get_val + [HashNode(nyckel, data)]
self.krock += 1
else:
## Create list
if get_val.get_nyckel() == nyckel:
self.dict[hashval] = HashNode(nyckel, data) ## Update old value
else:
self.dict[hashval] = [get_val, HashNode(nyckel, data)] ## Append to existing node
self.krock += 1
else:
self.dict[hashval] = HashNode(nyckel, data)
def __getitem__(self, nyckel):
return search(nyckel)
def __contains__(self, nyckel):
return (search(nyckel) != None)
def search(self, nyckel):
hashval = self.__hash(nyckel)
## Get val
get_val = self.dict.get(hashval)
if get_val == None:
raise KeyError("Key not found")
## Check if has multiple entries or not
if isinstance(get_val, list):
## Multiple
for value in get_val:
if(get_val.get_nyckel() == nyckel):
return get_val
raise KeyError("Key not found")
else:
## Single
if get_val.get_nyckel() == nyckel:
return get_val
else:
raise KeyError("Key not found")
## Hash function
def __hash(self, input):
inp = str(input) ## Get chars
value = 0
for k in input:
value += ord(k)
return (value % self.size)
def get_dict(self):
return self.dict
def get_krock(self):
return self.krock
Where the HashNode class is simply:
class HashNode:
def __init__(self, nyckel, data):
self.nyckel = nyckel
self.data = data
def get_nyckel(self):
return self.nyckel
def get_data(self):
return self.data
I've been staring myself blind with this issue for the past 2 weeks and I'm not getting any help from my lecturer/assistants, would greatly appreciate any advice on how to improve the speed.

Python convert object of class to int

I'm new in Python. And I have a task to make a double hash table for arrray and for doubly linked list. I have a code which work with array and code with doubly linked list. But I don't know how convert my object with linked_list to int. I know how convert it on Java just using class Integer but in Python I don't know. I tried to make a function def int(self) and return self.data but it doesn't work. I tried to find how make template or somethig like this but didn't find anything. Please help me.
This is a code:
from random import randint
class doubleHashTable:
# initialize hash Table
def __init__(self):
self.size = int(input("Enter the Size of the hash table : "))
self.num = 5
# initialize table with all elements 0
self.table = list(0 for i in range(self.size))
self.elementCount = 0
self.comparisons = 0
# method that checks if the hash table is full or not
def isFull(self):
if self.elementCount == self.size:
return True
else:
return False
# method that returns position for a given element
# replace with your own hash function
def h1(self, element):
return element % self.size
# method that returns position for a given element
def h2(self, element):
return element % self.num
# method to resolve collision by quadratic probing method
def doubleHashing(self, element, position):
posFound = False
# limit variable is used to restrict the function from going into infinite loop
# limit is useful when the table is 80% full
limit = 50
i = 2
# start a loop to find the position
while i <= limit:
# calculate new position by quadratic probing
newPosition = (i * self.h1(element) + self.h2(element)) % self.size
# if newPosition is empty then break out of loop and return new Position
if self.table[newPosition] == 0:
posFound = True
break
else:
# as the position is not empty increase i
i += 1
return posFound, newPosition
# method that inserts element inside the hash table
def insert(self, element):
# checking if the table is full
if self.isFull():
print("Hash Table Full")
return False
posFound = False
position = self.h1(element)
# checking if the position is empty
if self.table[position] == 0:
# empty position found , store the element and print the message
self.table[position] = element
print("Element " + str(element) + " at position " + str(position))
isStored = True
self.elementCount += 1
# collision occured hence we do linear probing
else:
while not posFound:
print("Collision has occured for element " + str(element) + " at position " + str(
position) + " finding new Position.")
posFound, position = self.doubleHashing(element, position)
if posFound:
self.table[position] = element
self.elementCount += 1
return posFound
# method that searches for an element in the table
# returns position of element if found
# else returns False
def search(self, element):
found = False
position = self.h1(element)
self.comparisons += 1
if (self.table[position] == element):
return position
# if element is not found at position returned hash function
# then we search element using double hashing
else:
limit = 50
i = 2
newPosition = position
# start a loop to find the position
while i <= limit:
# calculate new position by double Hashing
position = (i * self.h1(element) + self.h2(element)) % self.size
self.comparisons += 1
# if element at newPosition is equal to the required element
if self.table[position] == element:
found = True
break
elif self.table[position] == 0:
found = False
break
else:
# as the position is not empty increase i
i += 1
if found:
return position
else:
print("Element not Found")
return found
# method to remove an element from the table
def remove(self, element):
position = self.search(element)
if position is not False:
self.table[position] = 0
print("Element " + str(element) + " is Deleted")
self.elementCount -= 1
else:
print("Element is not present in the Hash Table")
return
# method to display the hash table
def display(self):
print("\n")
for i in range(self.size):
print(str(i) + " = " + str(self.table[i]))
print("The number of element is the Table are : " + str(self.elementCount))
"""DOUBLY-LINKED LIST"""
class Node():
def __init__(self, next_node=None, previous_node=None, data=None):
self.next_node = next_node
self.previous_node = previous_node
self.data = data
class LinkedList():
def __init__(self, node):
assert isinstance(node, Node)
self.first_node = node
self.last_node = node
def push(self, node):
'''Pushes the node <node> at the "front" of the ll
'''
node.next_node = self.first_node
node.previous_node = None
self.first_node.previous_node = node
self.first_node = node
def pop(self):
'''Pops the last node out of the list'''
old_last_node = self.last_node
to_be_last = self.last_node.previous_node
to_be_last.next_node = None
old_last_node.previous_node = None
# Set the last node to the "to_be_last"
self.previous_node = to_be_last
return old_last_node
def removing(self, node):
'''Removes and returns node, and connects the previous and next
'''
next_node = node.next_node
previous_node = node.previous_node
previous_node.next_node = next_node
next_node.previous_node = previous_node
# Make it "free"
node.next_node = node.previous_node = None
return node
# def int(self):
# return self.data
def __str__(self):
next_node = self.first_node
s = ""
while next_node:
s += "--({:2d})--\n".format(next_node.data)
next_node = next_node.next_node
return s
return
# main function
"""LISTS1"""
print("\nLISTS\n")
node1 = Node(data=1)
linked_list = LinkedList(node1)
for i in range(100):
if i == 5:
node1 = Node(data=5)
linked_list.push(node1)
else:
linked_list.push(Node(data=i))
print (linked_list)
print ("popping")
liast = linked_list.pop().data
#print(type(liast))
print(liast)
print (linked_list)
lalalal = linked_list
print(type(lalalal))
#print (linked_list.pop().data)
table_list1 = doubleHashTable()
for i in range (100):
table_list1.insert(lalalal)
# displaying the Table
table_list1.display()
print()
# printing position of elements
print("The position of element 31 is : " + str(table_list1.search(31)))
print("The position of element 28 is : " + str(table_list1.search(28)))
print("The position of element 90 is : " + str(table_list1.search(90)))
print("The position of element 77 is : " + str(table_list1.search(77)))
print("The position of element 1 is : " + str(table_list1.search(1)))
print("\nTotal number of comaprisons done for searching = " + str(table_list1.comparisons))
print()
table_list1.remove(90)
table_list1.remove(12)
table_list1.display()
# storing elements in table
# table1.insert(12)
# table1.insert(26)
# table1.insert(31)
# table1.insert(17)
# table1.insert(90)
# table1.insert(28)
# table1.insert(88)
# table1.insert(40)
# table1.insert(77) # element that causes collision at position 0
This is error
Traceback (most recent call last):
File "python", line 225, in <module>
File "python", line 57, in insert
File "python", line 22, in h1
TypeError: unsupported operand type(s) for %: 'LinkedList' and 'int'
short version use hash(element) on h1() and other places (h2()) at your code that use the hash of the object to determine is position in the hash table
you are inserting a linked_list lalalal
lalalal = linked_list
table_list1.insert(lalalal)
to calculate it's position you are using this method
def h1(self, element):
return element % self.size
you are trying to get mod from linked_list object and int, as the error state
you need to convert your linked list to some representation of number using some logic (uniform hash function is the best)
try to use smth like to_hash() on linked_list that will return int so
def h1(self, element):
return element.to_hash() % self.size
you can also override __hash__ and use hash(element)
Those few changes will make your code run
def h1(self, element):
return hash(element) % self.size
def h2(self, element):
return hash(element) % self.num
and in the LinkedList class add
def __hash__(self):
return randint(1, 1000)
Note: this hash function is for draft purpose only, in case your has map will be bigger than 1000 or what ever fixed value you choose, the elements won't be uniformly distributed over the map, this could effect the map performance...

Linked List Operations

Hello I need help trying to figure out these three functions. I am very new to python.
Assignment:
createList(srcSeq) - creates a linked list from the values
contained in the srcSeq sequence structure and returns the head
reference of the new linked list. The values will be added one at a
time by prepending them to the linked list. myValues = [5, 12, 82,
32, 20] myList = createList(myValues)
size(theList) - given the
head reference (theList), returns the number of elements in the
linked list.
printList(theList) - given the head reference
(theList), prints the values in the linked list from front to back
all on one line with the values separated by commas.
valueAt(theList, index) - returns the value contained in the node at
the given index position where the first value is at position 0, the
second at position 1 and so on. If index is out of range, return
None.
append(theList, value) - appends a new value to the end of
the linked list. Assume the list contains at least one node.
concat(listA, listB) - joins or concatenates two linked lists by
linking the last node of listA to the first node of listB.
split(theList) - given the head reference (theList), splits the
linked list in half to create two smaller linked lists. The head
reference of the linked list created from the second half of the list
is returned. Assume the list contains at least one node. If there is
an odd number of nodes in the linked list, the extra node can be
placed in either of the two new lists.
For the append, concat, do I simply just do. I do not know how to do the split method:
def append (theList, value):
current = self.head
while current.self.next != None:
current = self.next
current.newnode
def concat(listA, listB):
if listA.tail == None:
listA.head = listB.head
else:
listA.tail.next = listB.head
elif listB.head != None:
listA.tail = listB.tail
My Entire Code:
def createList( self ):
self.head = None
temp = ListNode( value )
self.next = newnext
temp.self.next(self.head)
self.head = temp
return self.head
def size( theList ):
current = self.head
count = 0
while current != None:
count = count + 1
current = current.self.next
return count
def printList( theList ):
node = self.head
while node:
print self.value
node = self.next
def valueAt( theList, index ):
current = head
count = 0
while current != None:
if count == index:
return current
def append( theList, value ):
current = self.head
while current.self.next != None:
current = self.next
current.newnode
def concat( listA, listB ):
if listA.tail == None:
listA.head = listB.head
else:
listA.tail.next = listB.head
elif listB.head != None:
listA.tail = listB.tail
def split( theList ):
pass
I think you problem is under-specified. but with what we have :
Splitting a singly linked list:
def split( head ):
middle = head
current = head
index = 0
while current.next != None:
if index % 2:
middle = middle.next
current = current.next
index += 1
result = middle.next
middle.next = None
return result
But to be honest, there is a lot more wrong with what you have so far.
If those lists were Python lists the solution would be really simple:
def split(a):
return a[:len(a)/2], a[len(a)/2:]
And now some explanation :) :
The function returns a tuple of two lists, where each list is one half of the supplied list a.
What I use above is called slicing and you can think of the colon character as of the word until. You can supply two _arguments beginning and end separated by that semicolon.
Example time!
a = [1,2,3,4,5]
a[:2] == [1,2]
a[2:] == [3,4,5]
a[1:3] == [2,3,4]
a[2,-2] == [3]
a[-3,-2] == [3,4]
Isn't slicing great? And it comes for free! One extra trick, if you want to make a copy of a list you can do that with slicing too!
b = a[:]
Boom, done! :)
There is more to slicing, you can have two colons, but that's a story for another time.
PS:
Out of curiosity I did your homework :)
class Node:
def __init__(self, data):
self.data = data
self.next = None
def __str__(self, *args, **kwargs):
return str(self.data)
def create_list(iterable):
next_node = current_node = None
for item in iterable:
current_node = Node(item)
current_node.next = next_node
next_node = current_node
return current_node
def size(head):
count = 0
while head:
head = head.next
count += 1
return count
def print_list(head):
while head:
print(head, end="")
if head.next:
print(" > ", end="")
head = head.next
print(flush=True)
pass
def value_at(head, index):
while (head):
if index < 1:
return head
index -= 1
head = head.next
return None
def append(head, value):
while head:
if not head.next:
head.next = Node(value)
return
head = head.next
def concat(headA, headB):
while headA:
if not headA.next:
headA.next = headB
return
headA = headA.next
def split(head):
center = head
index = 0
while head:
if index % 2:
center = center.next
head = head.next
index += 1
headB = center.next
center.next = None
return headB
def main():
a = create_list([1, 2, 3, 4, 5, 6, 7, 8, 9])
print("Print list::")
print_list(a)
print("\nSize:")
print(size(a))
print("\nValue at:")
print("a[-1]: %d" % value_at(a, -1).data)
print("a[0]: %d" % value_at(a, 0).data)
print("a[1]: %d" % value_at(a, 1).data)
print("a[5]: %d" % value_at(a, 5).data)
print("a[8]: %d" % value_at(a, 8).data)
# print("value # 9 %d"% value_at(my_head,9).data)
print("\nAppend (10):")
print_list(a)
append(a, 10)
print_list(a)
print("\nConcat a, b:")
print_list(a)
b = create_list([11, 12, 13])
print_list(b)
concat(a, b)
print_list(a)
print("\nSplit:")
print_list(a)
print("..into..")
b = split(a)
print_list(a)
print("Size a: %d" % size(a))
print_list(b)
print("Size b: %d" % size(b))
if __name__ == "__main__":
main()

Give equal items in list a unique number if items > 1

I made a functionality, but I not happy with the quantity of the code. The end result is good, but I believe it can be made much easier, only I don't know how.
The functionality: If equal items > 1 in list that all equal items getting unique set number. Below I made an unit test for the end result. I'm not happy with the class CreatSet. Can somebody advise me how this can be implemented better.
import unittest
class Curtain(object):
def __init__(self, type, fabric, number):
self.type = type
self.fabric = fabric
self.number = number
self.set_number = None
def __str__(self):
return '%s %s %s %s' % (self.number, self.type, self.fabric, self.set_name)
def __eq__(self, other):
return self.type == other.type and self.fabric == other.fabric
class CreatSet(object):
def make_unique(self, original_list):
checked = []
for e in original_list:
# If curtain: type and fabric is equal
if e not in checked:
checked.append(e)
return checked
def create_set(self, curtains):
# Uniuqe items in list
unique_list = self.make_unique(curtains)
result = []
for x in unique_list:
# Create set list
set_range = []
for y in curtains:
if y == x:
set_range.append(y)
# Add set range into list
result.append(set_range)
# Create set number
set_result = []
set_number = 0
for x in result:
if len(x) == 1:
set_result.append(x[0])
else:
set_number += 1
for y in x:
y.set_number = set_number
set_result.append(y)
# Return list ordered by number
return sorted(set_result, key=lambda curtain: curtain.number)
class TestCreateSet(unittest.TestCase):
def setUp(self):
self.curtains = []
self.curtains.append(Curtain('pleatcurtain', 'pattern', 0))
self.curtains.append(Curtain('pleatcurtain', 'plain', 1))
self.curtains.append(Curtain('pleatcurtain', 'pattern', 2))
self.curtains.append(Curtain('foldcurtain', 'pattern', 3))
self.curtains.append(Curtain('pleatcurtain', 'plain', 4))
self.curtains.append(Curtain('foldcurtain', 'plain', 5))
self.curtains.append(Curtain('pleatcurtain', 'pattern', 6))
self.curtains.append(Curtain('foldcurtain', 'pattern', 7))
def test_auto_set(self):
creat_set = CreatSet()
result = creat_set.create_set(self.curtains)
# Creating set
self.assertEqual(result[0].set_number, 1) # pleatcurtain, pattern
self.assertEqual(result[1].set_number, 2) # pleatcurtain, plain
self.assertEqual(result[2].set_number, 1) # pleatcurtain, pattern
self.assertEqual(result[3].set_number, 3) # foldcurtain, pattern
self.assertEqual(result[4].set_number, 2) # pleatcurtain, plain
self.assertEqual(result[5].set_number, None) # foldcurtain, plain
self.assertEqual(result[6].set_number, 1) # pleatcurtain, pattern
self.assertEqual(result[7].set_number, 3) # foldcurtain, pattern
if __name__ == '__main__':
unittest.main()

Categories