diff --git a/class-30/challenge/hashtable.py b/class-30/challenge/hashtable.py new file mode 100644 index 0000000..6a958e3 --- /dev/null +++ b/class-30/challenge/hashtable.py @@ -0,0 +1,92 @@ +from data_structures.linked_list import LinkedList + + +class Hashtable: + """ + Put docstring here + """ + + def __init__(self, size=1024): + self._size = size + self._buckets = [None] * size + + def set(self, key, value): + index = self._hash(key) + bucket = self._buckets[index] + if bucket is None: + bucket = LinkedList() + self._buckets[index] = bucket + + current = bucket.head + + while current: + candidate_drop = current.value + if candidate_drop[0] == key: + # found preexisting drop + candidate_drop[1] = value # update the value + return + + drop = [key, value] # no prexisting drop, add the drop aka key-value pair + bucket.insert(drop) + + def get(self, key): + index = self._hash(key) + + bucket = self._buckets[index] + + if bucket is None: + return None + + current = bucket.head + + while current: + drop = current.value # key value pair + if drop[0] == key: + return drop[1] + + current = current.next + + return None + + def keys(self): + """ + return list of keys + """ + key_list = [] # list of strings + + for bucket in self._buckets: # list of LinkedLists (or None) + if bucket: # LinkedList + current = bucket.head # Node + while current: + drop = current.value # List of 2 items [key, value] + key_list.append(drop[0]) + current = current.next + + return key_list + + def has(self, key): + for bucket in self._buckets: # list of LinkedLists (or None) + if bucket: # LinkedList + current = bucket.head # Node + while current: + drop = current.value # List of 2 items [key, value] + if drop[0] == key: + return True + + current = current.next + + return False + + def _hash(self, key): + """ + Add all the ASCII values together. + Multiply it by a prime number such as 599. + Use modulo to get the remainder of the result, when divided by the total size of the array. + """ + index = 0 + for char in key: + index += ord(char) + index *= 599 + index = index % self._size + + return index diff --git a/class-30/challenge/test_hashtable.py b/class-30/challenge/test_hashtable.py new file mode 100644 index 0000000..2737de2 --- /dev/null +++ b/class-30/challenge/test_hashtable.py @@ -0,0 +1,107 @@ +import pytest +from data_structures.hashtable import Hashtable + + +def test_exists(): + assert Hashtable + + +@pytest.mark.skip("TODO") +def test_hash(): + """ + NOTE: intentionally breaks "encapsulation" by accessing "internal" attriubutes + """ + hashtable = Hashtable() + actual = hashtable._hash("Zach") + assert 0 <= actual < hashtable._size + + +@pytest.mark.skip("TODO") +def test_hash_twice(): + """ + NOTE: intentionally breaks "encapsulation" by accessing "internal" attriubutes + """ + hashtable = Hashtable() + first = hashtable._hash("Zach") + second = hashtable._hash("Zach") + assert first == second + + +@pytest.mark.skip("TODO") +def test_apple(): + hashtable = Hashtable() + hashtable.set("apple", "Used for apple sauce") + actual = hashtable.get("apple") + expected = "Used for apple sauce" + assert actual == expected + + +@pytest.mark.skip("TODO") +def test_apple_again(): + hashtable = Hashtable() + hashtable.set("apple", "Used for apple sauce") + hashtable.set("apple", "Can give to teacher") + actual = hashtable.get("apple") + expected = "Can give to teacher" + assert actual == expected + + +@pytest.mark.skip("TODO") +def test_key_not_exists(): + hashtable = Hashtable() + actual = hashtable.get("nonexisting key") + expected = None + assert actual == expected + + +@pytest.mark.skip("TODO") +def test_key_not_exists_again(): + """ + WARNING: requires that act & cat hash the same + """ + hashtable = Hashtable() + hashtable.set("cat", "meow") + actual = hashtable.get("act") + expected = None + assert actual == expected + + +@pytest.mark.skip("TODO") +def test_keys(): + hashtable = Hashtable() + hashtable.set("apple", "Used for apple sauce") + hashtable.set("banana", "Great in a banana split") + actual = hashtable.keys() + expected = ["apple", "banana"] + assert sorted(actual) == sorted(expected) + + +@pytest.mark.skip("TODO") +def test_has(): + hashtable = Hashtable() + hashtable.set("apple", "Used for apple sauce") + hashtable.set("banana", "Great in a banana split") + assert hashtable.has("apple") + assert hashtable.has("banana") + assert not hashtable.has("cucumber") + + +@pytest.mark.skip("TODO") +def test_keys_repeats(): + hashtable = Hashtable() + hashtable.set("apple", "Used for apple sauce") + hashtable.set("apple", "Can give to teacher") + hashtable.set("banana", "Great in a banana split") + actual = hashtable.keys() + expected = ["apple", "banana"] + assert sorted(actual) == sorted(expected) + + +@pytest.mark.skip("TODO") +def test_internals(): + """ + NOTE: there's a test_internals in your DSA repo that isn't a great fit. + Feel free to ignore it + Or tweak it as a STRETCH + """ + pass