-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |