From 27aca89ce3be7467eba1970513f80090e23bec98 Mon Sep 17 00:00:00 2001 From: chad-scanlon <59572157+chad-scanlon@users.noreply.github.com> Date: Wed, 28 Oct 2020 12:44:55 -0400 Subject: [PATCH 1/4] Day 1 tests passing --- hashtable/hashtable.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 0205f0ba9..29a2d372b 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -22,6 +22,9 @@ class HashTable: def __init__(self, capacity): # Your code here + self.total = 0 + self.capacity = capacity + self.storage = [None] * capacity def get_num_slots(self): @@ -35,6 +38,8 @@ def get_num_slots(self): Implement this. """ # Your code here + + return self.capacity def get_load_factor(self): @@ -44,6 +49,7 @@ def get_load_factor(self): Implement this. """ # Your code here + pass def fnv1(self, key): @@ -54,6 +60,7 @@ def fnv1(self, key): """ # Your code here + pass def djb2(self, key): @@ -63,6 +70,10 @@ def djb2(self, key): Implement this, and/or FNV-1. """ # Your code here + hash_value = 5381 + for c in key: + hash_value = ((hash_value << 5) + hash_value) + ord(c) + return hash_value & 0xFFFFFFFF def hash_index(self, key): @@ -82,6 +93,15 @@ def put(self, key, value): Implement this. """ # Your code here + new_node = HashTableEntry(key, value) + index = self.hash_index(key) + if self.storage[index] == None: + self.storage[index] = new_node + + elif self.storage[index].key == key: + self.storage[index].value = value + + def delete(self, key): @@ -93,7 +113,14 @@ def delete(self, key): Implement this. """ # Your code here + index = self.hash_index(key) + + if self.storage[index].key == key: + self.storage[index] = None + + + def get(self, key): """ @@ -104,6 +131,17 @@ def get(self, key): Implement this. """ # Your code here + + index = self.hash_index(key) + node = self.storage[index] + + if node is not None: + + if node.key == key: + return node.value + + + def resize(self, new_capacity): @@ -114,6 +152,7 @@ def resize(self, new_capacity): Implement this. """ # Your code here + return self.capacity * 2 From df8792cf666e988e9ec744ef2b5e1716f0f683c4 Mon Sep 17 00:00:00 2001 From: chad-scanlon <59572157+chad-scanlon@users.noreply.github.com> Date: Mon, 2 Nov 2020 09:22:35 -0500 Subject: [PATCH 2/4] Day 2 tests passing --- hashtable/hashtable.py | 161 ++++++++++++++++------------- hashtable/test_hashtable_resize.py | 1 + 2 files changed, 91 insertions(+), 71 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 29a2d372b..df6b136b4 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -6,6 +6,8 @@ def __init__(self, key, value): self.key = key self.value = value self.next = None + # def __repr__(self): + # return f"{self.key}, {self.value}" # Hash table can't have fewer than this many slots @@ -22,34 +24,21 @@ class HashTable: def __init__(self, capacity): # Your code here - self.total = 0 self.capacity = capacity self.storage = [None] * capacity + self.total = 0 + def get_num_slots(self): - """ - Return the length of the list you're using to hold the hash - table data. (Not the number of items stored in the hash table, - but the number of slots in the main list.) - - One of the tests relies on this. - - Implement this. - """ - # Your code here - - return self.capacity + + return len(self.storage) def get_load_factor(self): - """ - Return the load factor for this hash table. - - Implement this. - """ - # Your code here - pass + + return self.total / self.capacity + # pass def fnv1(self, key): @@ -85,76 +74,102 @@ def hash_index(self, key): return self.djb2(key) % self.capacity def put(self, key, value): - """ - Store the value with the given key. + + + # Day 1 + # new_node = HashTableEntry(key, value) + # index = self.hash_index(key) + # if self.storage[index] == None: + # self.storage[index] = new_node + + # elif self.storage[index].key == key: + # self.storage[index].value = value + index = self.hash_index(key) + cur_entry = self.storage[index] - Hash collisions should be handled with Linked List Chaining. + while cur_entry is not None and cur_entry != key: + cur_entry = cur_entry.next - Implement this. - """ - # Your code here - new_node = HashTableEntry(key, value) - index = self.hash_index(key) - if self.storage[index] == None: - self.storage[index] = new_node - - elif self.storage[index].key == key: - self.storage[index].value = value - + if cur_entry is not None: + cur_entry.value = value + else: + new_entry = HashTableEntry(key, value) + new_entry.next = self.storage[index] + self.storage[index] = new_entry + + self.total += 1 + if self.get_load_factor() > 0.7: + self.resize(self.capacity * 2) + def delete(self, key): - """ - Remove the value stored with the given key. - - Print a warning if the key is not found. - - Implement this. - """ - # Your code here + + # Day 1 + # index = self.hash_index(key) + # if self.storage[index].key == key: + # self.storage[index] = None index = self.hash_index(key) - - if self.storage[index].key == key: - self.storage[index] = None + current_entry = self.storage[index] + last_entry = None + + while current_entry is not None and current_entry.key != key: + last_entry = current_entry + current_entry = last_entry.next + + if current_entry is None: + print("ERROR: Unable to remove entry with key " + key) + else: + if last_entry is None: + self.storage[index] = current_entry.next + else: + last_entry.next = current_entry.next + + self.total -= 1 + if self.get_load_factor() < 0.2: + if self.capacity > MIN_CAPACITY: + new_capacity = self.capacity // 2 + if new_capacity < MIN_CAPACITY: + new_capacity = MIN_CAPACITY + + self.resize(new_capacity) - - - def get(self, key): - """ - Retrieve the value stored with the given key. - - Returns None if the key is not found. - Implement this. - """ - # Your code here - - index = self.hash_index(key) - node = self.storage[index] + # Day 1 + # index = self.hash_index(key) + # node = self.storage[index] - if node is not None: + # if node is not None: - if node.key == key: - return node.value - - + # if node.key == key: + # return node.value + index = self.hash_index(key) + if (self.storage[index] and self.storage[index].key == key): + return self.storage[index].value + else: + return None + def resize(self, new_capacity): + old_storage = self.storage + self.capacity = new_capacity + self.storage = [None] * self.capacity - def resize(self, new_capacity): - """ - Changes the capacity of the hash table and - rehashes all key/value pairs. + cur_entry = None + old_total = self.total - Implement this. - """ - # Your code here - return self.capacity * 2 + for total_item in old_storage: + cur_entry = total_item + while cur_entry is not None: + self.put(cur_entry.key, cur_entry.value) + cur_entry = cur_entry.next + self.total = old_total + if __name__ == "__main__": ht = HashTable(8) @@ -175,6 +190,10 @@ def resize(self, new_capacity): print("") # Test storing beyond capacity + print("Should only print 8 lines") + print(" ") + print(f"Prints {ht.capacity} lines") + print(" ") for i in range(1, 13): print(ht.get(f"line_{i}")) diff --git a/hashtable/test_hashtable_resize.py b/hashtable/test_hashtable_resize.py index 02ba7b316..bf074c203 100644 --- a/hashtable/test_hashtable_resize.py +++ b/hashtable/test_hashtable_resize.py @@ -170,6 +170,7 @@ def test_hash_table_resize(self): ht.resize(1024) self.assertTrue(ht.get_num_slots() == 1024) + return_value = ht.get("key-0") self.assertTrue(return_value == "val-0") From d2215e2b9d2eb331faee880f18bbdfdd637b69c0 Mon Sep 17 00:00:00 2001 From: chad-scanlon <59572157+chad-scanlon@users.noreply.github.com> Date: Tue, 3 Nov 2020 16:53:05 -0500 Subject: [PATCH 3/4] 1st half of application exercises --- applications/expensive_seq/expensive_seq.py | 19 +++++++++-- applications/lookup_table/lookup_table.py | 21 ++++++++++++ applications/no_dups/no_dups.py | 11 ++++++ applications/word_count/word_count.py | 37 ++++++++++++++++++++- 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/applications/expensive_seq/expensive_seq.py b/applications/expensive_seq/expensive_seq.py index 5c82b8453..00d155e21 100644 --- a/applications/expensive_seq/expensive_seq.py +++ b/applications/expensive_seq/expensive_seq.py @@ -1,8 +1,23 @@ # Your code here - - +# exps(x, y, z) = + # if x <= 0: y + z + # if x > 0: exps(x-1,y+1,z) + exps(x-2,y+2,z*2) + exps(x-3,y+3,z*3) + +nums = {} def expensive_seq(x, y, z): # Your code here + if (x, y, z) in nums.keys(): + return nums[(x, y, z)] + + if x <= 0: + return y + z + + if x > 0: + value = expensive_seq(x-1, y+1, z) + expensive_seq(x-2, + y+2, z*2) + expensive_seq(x-3, y+3, z*3) + + nums[(x, y, z)] = value + return value diff --git a/applications/lookup_table/lookup_table.py b/applications/lookup_table/lookup_table.py index 05b7d37fa..e631da6ad 100644 --- a/applications/lookup_table/lookup_table.py +++ b/applications/lookup_table/lookup_table.py @@ -1,4 +1,8 @@ # Your code here +import math +import random + + def slowfun_too_slow(x, y): @@ -9,12 +13,24 @@ def slowfun_too_slow(x, y): return v +nums = {} + def slowfun(x, y): """ Rewrite slowfun_too_slow() in here so that the program produces the same output, but completes quickly instead of taking ages to run. """ # Your code here + if (x, y) in nums.keys(): + return nums[(x, y)] + + v = math.pow(x, y) + v = math.factorial(v) + v //= (x + y) + v %= 982451653 + nums[(x, y)] = v + + return v @@ -24,3 +40,8 @@ def slowfun(x, y): x = random.randrange(2, 14) y = random.randrange(3, 6) print(f'{i}: {x},{y}: {slowfun(x, y)}') + +# for i in range(50000): +# x = random.randrange(2, 14) +# y = random.randrange(3, 6) +# print(f'{i}: {x},{y}: {slowfun_too_slow(x, y)}') diff --git a/applications/no_dups/no_dups.py b/applications/no_dups/no_dups.py index caa162c8c..bffff484e 100644 --- a/applications/no_dups/no_dups.py +++ b/applications/no_dups/no_dups.py @@ -1,5 +1,16 @@ def no_dups(s): # Your code here + duplicates = {} + sentence = "" + + words = s.split() + + for word in words: + if word not in duplicates.keys(): + duplicates[word] = word + sentence += word + " " + sentence = sentence[:-1] + return sentence diff --git a/applications/word_count/word_count.py b/applications/word_count/word_count.py index a20546425..a0171541a 100644 --- a/applications/word_count/word_count.py +++ b/applications/word_count/word_count.py @@ -1,6 +1,41 @@ def word_count(s): - # Your code here + # Your code here + words = s.replace(",", "") + words = words.replace(".", "") + words = words.replace("\"", "") + words = words.replace(":", "") + words = words.replace(";", "") + words = words.replace("-", "") + words = words.replace("+", "") + words = words.replace("=", "") + words = words.replace("/", "") + words = words.replace("\\", "") + words = words.replace("|", "") + words = words.replace("[", "") + words = words.replace("]", "") + words = words.replace("{", "") + words = words.replace("}", "") + words = words.replace("(", "") + words = words.replace(")", "") + words = words.replace("*", "") + words = words.replace("^", "") + words = words.replace("&", "") + words = words.lower() + words = words.split() + + + count = {} + for word in words: + # if not word.isalpha(): + # continue + if word in count.keys(): + count[word] += 1 + else: + count[word] = 1 + + + return count if __name__ == "__main__": From de686be53044148f07bfb379d405d88f7019321a Mon Sep 17 00:00:00 2001 From: chad-scanlon <59572157+chad-scanlon@users.noreply.github.com> Date: Fri, 6 Nov 2020 09:44:03 -0500 Subject: [PATCH 4/4] Another application exercise completed --- applications/histo/histo.py | 3 +- applications/markov/markov.py | 63 +++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/applications/histo/histo.py b/applications/histo/histo.py index 6014a8e13..1fae32588 100644 --- a/applications/histo/histo.py +++ b/applications/histo/histo.py @@ -1,2 +1,3 @@ # Your code here - +with open("applications/histo/robin.txt") as f: + words = f.read() diff --git a/applications/markov/markov.py b/applications/markov/markov.py index 1d138db10..5230a5157 100644 --- a/applications/markov/markov.py +++ b/applications/markov/markov.py @@ -1,13 +1,72 @@ import random # Read in all the words in one go -with open("input.txt") as f: +with open("applications/markov/input.txt") as f: words = f.read() # TODO: analyze which words can follow other words # Your code here + word_list = words.split() + markov = {} + last_word = None + for index in range(1, len(word_list)): + last_word = word_list[index - 1] + word = word_list[index] + if last_word not in markov.keys(): + markov[last_word] = [word] + else: + markov[last_word].append(word) + + # print(markov) # TODO: construct 5 random sentences -# Your code here + select_word = word_list[random.randint(0, len(word_list)-1)] + sentence = select_word + " " + for word in range(20): + words = markov[select_word] + select_word = words[random.randint(0, len(words)-1)] + sentence += select_word + " " + + print("") + print(sentence) + + select_word = word_list[random.randint(0, len(word_list)-1)] + sentence = select_word + " " + for word in range(20): + words = markov[select_word] + select_word = words[random.randint(0, len(words)-1)] + sentence += select_word + " " + + print("") + print(sentence) + + select_word = word_list[random.randint(0, len(word_list)-1)] + sentence = select_word + " " + for word in range(20): + words = markov[select_word] + select_word = words[random.randint(0, len(words)-1)] + sentence += select_word + " " + + print("") + print(sentence) + + select_word = word_list[random.randint(0, len(word_list)-1)] + sentence = select_word + " " + for word in range(20): + words = markov[select_word] + select_word = words[random.randint(0, len(words)-1)] + sentence += select_word + " " + + print("") + print(sentence) + + select_word = word_list[random.randint(0, len(word_list)-1)] + sentence = select_word + " " + for word in range(20): + words = markov[select_word] + select_word = words[random.randint(0, len(words)-1)] + sentence += select_word + " " + print("") + print(sentence)