From 1e70ab10f160d34620a3769cf327a14cbd06b30f Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Wed, 28 Oct 2020 18:59:46 -0700 Subject: [PATCH 1/8] MVP met for Day 1 --- hashtable/hashtable.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 0205f0ba9..30a2212d0 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -2,6 +2,7 @@ class HashTableEntry: """ Linked List hash table key/value pair """ + def __init__(self, key, value): self.key = key self.value = value @@ -22,8 +23,8 @@ class HashTable: def __init__(self, capacity): # Your code here - - + self.capacity = capacity + self.data = [None] * capacity def get_num_slots(self): """ Return the length of the list you're using to hold the hash @@ -35,6 +36,7 @@ def get_num_slots(self): Implement this. """ # Your code here + return self.capacity def get_load_factor(self): @@ -44,6 +46,7 @@ def get_load_factor(self): Implement this. """ # Your code here + def fnv1(self, key): @@ -63,6 +66,10 @@ def djb2(self, key): Implement this, and/or FNV-1. """ # Your code here + hash = 5381 + for c in key: + hash = (hash * 33) + ord(c) + return hash def hash_index(self, key): @@ -70,7 +77,7 @@ def hash_index(self, key): Take an arbitrary key and return a valid integer index between within the storage capacity of the hash table. """ - #return self.fnv1(key) % self.capacity + # return self.fnv1(key) % self.capacity return self.djb2(key) % self.capacity def put(self, key, value): @@ -82,6 +89,8 @@ def put(self, key, value): Implement this. """ # Your code here + index = self.hash_index(key) + self.data[index] = value def delete(self, key): @@ -93,6 +102,11 @@ def delete(self, key): Implement this. """ # Your code here + index = self.hash_index(key) + if self.data[index] is None: + print("Error: Key not found") + else: + self.data[index] = None def get(self, key): @@ -104,6 +118,9 @@ def get(self, key): Implement this. """ # Your code here + index = self.hash_index(key) + value = self.data[index] + return value def resize(self, new_capacity): From 5ee3f7f7559ee0db66df3e0e39d24071df3a4781 Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Fri, 30 Oct 2020 20:11:44 -0700 Subject: [PATCH 2/8] Day 2 MVP Met/Sprint --- hashtable/hashtable.py | 137 ++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 42 deletions(-) diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 30a2212d0..45c78f2c2 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -2,7 +2,6 @@ class HashTableEntry: """ Linked List hash table key/value pair """ - def __init__(self, key, value): self.key = key self.value = value @@ -12,64 +11,64 @@ def __init__(self, key, value): # Hash table can't have fewer than this many slots MIN_CAPACITY = 8 +MAX_LOAD_FACTOR = 0.7 +MIN_LOAD_FACTOR = 0.2 class HashTable: """ A hash table that with `capacity` buckets that accepts string keys - Implement this. """ - def __init__(self, capacity): - # Your code here + def __init__(self, capacity=MIN_CAPACITY): self.capacity = capacity - self.data = [None] * capacity + self.array = [None] * capacity + self.items = 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 def get_load_factor(self): """ Return the load factor for this hash table. - Implement this. """ - # Your code here - + return self.items / self.capacity def fnv1(self, key): """ FNV-1 Hash, 64-bit - Implement this, and/or DJB2. """ - # Your code here + hash = 14638081039346656478 # Offset + + for s in key: + hash = hash * 1099511628211 # FVN prime + hash = hash ^ ord(s) + return hash % len(self.array) def djb2(self, key): """ DJB2 hash, 32-bit - Implement this, and/or FNV-1. """ - # Your code here hash = 5381 - for c in key: - hash = (hash * 33) + ord(c) - return hash + + for x in key: + hash = ((hash << 5) + hash) + ord(x) + return hash & 0xffffffff % self.capacity def hash_index(self, key): @@ -77,61 +76,115 @@ def hash_index(self, key): Take an arbitrary key and return a valid integer index between within the storage capacity of the hash table. """ - # return self.fnv1(key) % self.capacity + #return self.fnv1(key) % self.capacity return self.djb2(key) % self.capacity def put(self, key, value): """ Store the value with the given key. - Hash collisions should be handled with Linked List Chaining. - Implement this. """ - # Your code here index = self.hash_index(key) - self.data[index] = value + + entry = self.array[index] + + if entry is None: + self.array[index] = HashTableEntry(key, value) + self.items += 1 + self.resizeIfNeeded() + return + + while entry.next != None and entry.key !=key: + entry = entry.next + + if entry.key == key: + entry.value = value + else: + entry.next = HashTableEntry(key, value) + self.items += 1 + self.resizeIfNeeded() 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 index = self.hash_index(key) - if self.data[index] is None: - print("Error: Key not found") - else: - self.data[index] = None + entry = self.array[index] + prev_entry = None - def get(self, key): - """ - Retrieve the value stored with the given key. + if entry is not None: + while entry.next != None and entry.key != key: + prev_entry = entry + entry = entry.next - Returns None if the key is not found. + if entry.key == key: + if prev_entry is None: + self.array[index] = entry.next + else: + prev_entry.next = entry.next + self.items -= 1 + self.resizeIfNeeded() + return + + print(f"Warning: Attempted to delete value from HashTable but no value exists for key '{key}'") + + + def get(self, key): + - Implement this. - """ - # Your code here index = self.hash_index(key) - value = self.data[index] - return value + entry = self.array[index] + + if entry is None: + return None + + while entry.next != None and entry.key != key: + entry = entry.next + + return entry.value if entry.key == key else None + + + def resizeIfNeeded(self): + if self.get_load_factor () > MAX_LOAD_FACTOR: + self.resize(self.capacity * 2) + elif self.get_load_factor() < MIN_LOAD_FACTOR and int(self.capacity / 2) >= MIN_CAPACITY: + self.resize(int(self.capacity / 2)) def resize(self, new_capacity): """ Changes the capacity of the hash table and rehashes all key/value pairs. - Implement this. """ - # Your code here + old_array = self.array + self.array = [None] * new_capacity + self.capacity = new_capacity + + for old_entry in old_array: + while old_entry is not None: + key = old_entry.key + value = old_entry.value + index = self.hash_index(key) + entry = self.array[index] + + # inserts old key/value into resized hash table + + if entry is None: + self.array[index] = HashTableEntry(key, value) + else: + while entry.next != None: + entry = entry.next + entry.next = HashTableEntry(key, value) + + old_entry = old_entry.next + if __name__ == "__main__": @@ -167,4 +220,4 @@ def resize(self, new_capacity): for i in range(1, 13): print(ht.get(f"line_{i}")) - print("") + print("") \ No newline at end of file From cc3cc7891f61e9d6960e92c961974a1c45a2d0f5 Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Tue, 3 Nov 2020 19:58:15 -0800 Subject: [PATCH 3/8] added_expseq --- applications/expensive_seq/expensive_seq.py | 13 +++++++++++-- hashtable/hashtable.py | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/applications/expensive_seq/expensive_seq.py b/applications/expensive_seq/expensive_seq.py index 5c82b8453..866d437c5 100644 --- a/applications/expensive_seq/expensive_seq.py +++ b/applications/expensive_seq/expensive_seq.py @@ -1,9 +1,18 @@ # Your code here - +dictionary = {} def expensive_seq(x, y, z): - # Your code here + if (x, y, z) in dictionary: + return dictionary[(x, y, z)] + + result = 0 + if x <= 0: + result = y + z + if x > 0: + result = expensive_seq(x-1,y+1,z) + expensive_seq(x-2,y+2,z*2) + expensive_seq(x-3,y+3,z*3) + dictionary[(x, y, z)] = result + return result if __name__ == "__main__": diff --git a/hashtable/hashtable.py b/hashtable/hashtable.py index 45c78f2c2..4e972a20b 100644 --- a/hashtable/hashtable.py +++ b/hashtable/hashtable.py @@ -42,7 +42,7 @@ def get_load_factor(self): Return the load factor for this hash table. Implement this. """ - return self.items / self.capacity + return self.items / self.get_num_slots() def fnv1(self, key): From 4440117ff170d1b3aca3288fed722709a42251a8 Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Tue, 3 Nov 2020 20:12:11 -0800 Subject: [PATCH 4/8] added_lookuptable --- applications/lookup_table/lookup_table.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/applications/lookup_table/lookup_table.py b/applications/lookup_table/lookup_table.py index 05b7d37fa..7b94a5383 100644 --- a/applications/lookup_table/lookup_table.py +++ b/applications/lookup_table/lookup_table.py @@ -1,22 +1,24 @@ -# Your code here +import math +import random +dictionary = {} -def slowfun_too_slow(x, y): - v = math.pow(x, y) - v = math.factorial(v) - v //= (x + y) - v %= 982451653 - return v 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 dictionary: + return dictionary[(x, y)] + v = math.pow(x, y) + v = math.factorial(v) + v //= (x + y) + v %= 982451653 + dictionary[(x, y)] = v + return v # Do not modify below this line! From adb726302c1d3aaad4b7788430f6cfddec024c9e Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Tue, 3 Nov 2020 20:51:48 -0800 Subject: [PATCH 5/8] added_no_dups --- applications/no_dups/no_dups.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/applications/no_dups/no_dups.py b/applications/no_dups/no_dups.py index caa162c8c..ab9ca01fb 100644 --- a/applications/no_dups/no_dups.py +++ b/applications/no_dups/no_dups.py @@ -1,6 +1,20 @@ def no_dups(s): - # Your code here + array = [] + result_string = "" + split_string = s.split() + + if s == "": + return result_string + for word in split_string: + if word not in array: + array.append(word) + result_string += word + " " + + if result_string.endswith(" "): + return result_string[:-1] + + return result_string if __name__ == "__main__": From 5f47792f03e6bee8a4ff4760f7db9399e39d1d23 Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Tue, 3 Nov 2020 21:28:05 -0800 Subject: [PATCH 6/8] added_word_count --- applications/word_count/word_count.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/applications/word_count/word_count.py b/applications/word_count/word_count.py index a20546425..dc2dabc32 100644 --- a/applications/word_count/word_count.py +++ b/applications/word_count/word_count.py @@ -1,6 +1,22 @@ def word_count(s): - # Your code here + dictionary = {} + special_characters = ['"', ":", ";", ",", ".", "-", "+", "=", "/", "|", "[", "]", "{", "}", "(", ")", "*", "^", "&", "\\"] + lower_case = s.lower() + + for i in special_characters: + lower_case = lower_case.replace(i, "") + + split_string = lower_case.split() + if split_string.count == 0: + return dictionary + + for word in split_string: + if word in dictionary: + dictionary[word] += 1 + else: + dictionary[word] = 1 + return dictionary if __name__ == "__main__": From bfaea6b36cc9e0d75359e1595e0ca1767a4f65b2 Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Thu, 5 Nov 2020 18:10:08 -0800 Subject: [PATCH 7/8] added crack_caesar --- applications/crack_caesar/crack_caesar.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/applications/crack_caesar/crack_caesar.py b/applications/crack_caesar/crack_caesar.py index 1418f0ef3..a36db7c89 100644 --- a/applications/crack_caesar/crack_caesar.py +++ b/applications/crack_caesar/crack_caesar.py @@ -1,5 +1,20 @@ + # Use frequency analysis to find the key to ciphertext.txt, and then # decode it. # Your code here +import os + +f = open(f"{os.getcwd()}/applications/crack_caesar/ciphertext.txt") + +text = f.read() +print(text) + + +letter_frequencies = {'E': 11.53, 'T': 9.75, 'A': 8.46, 'O': 8.08, 'H': 7.71, + 'N': 6.73, 'R': 6.29, 'I': 5.84, 'S': 5.56, 'D': 4.74, + 'L': 3.92, 'W': 3.08, 'U': 2.59, 'G': 2.48, 'F': 2.42, + 'B': 2.19, 'M': 2.18, 'Y': 2.02, 'C': 1.58, 'P': 1.08, + 'K': 0.84, 'V': 0.59, 'Q': 0.17, 'J': 0.07, 'X': 0.07, + 'Z': 0.03} \ No newline at end of file From b3a41e13dedac8eaae96bbe8552d72c09c6d59b6 Mon Sep 17 00:00:00 2001 From: msteele11101 Date: Thu, 5 Nov 2020 20:35:07 -0800 Subject: [PATCH 8/8] finished some --- applications/histo/histo.py | 4 ++-- applications/markov/markov.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/applications/histo/histo.py b/applications/histo/histo.py index 6014a8e13..23aa50813 100644 --- a/applications/histo/histo.py +++ b/applications/histo/histo.py @@ -1,2 +1,2 @@ -# Your code here - + +# Your code here \ No newline at end of file diff --git a/applications/markov/markov.py b/applications/markov/markov.py index 1d138db10..017dda14b 100644 --- a/applications/markov/markov.py +++ b/applications/markov/markov.py @@ -10,4 +10,3 @@ # TODO: construct 5 random sentences # Your code here -