Skip to content

Commit

Permalink
Merge pull request #5 from famavott/hash
Browse files Browse the repository at this point in the history
Hash
  • Loading branch information
famavott committed Dec 3, 2017
2 parents 7c2c42a + 29dffe7 commit 2e94770
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 1 deletion.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ language: python

python:
- '3.6'
- '2.7'

notifications:
- email: false
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,17 @@ Time Complexity: O(n)
Delete(self, data): Removes a value if present, otherwise returns nothing. Returns None in all cases.

Time Complexity: O(n)

## Hash Table

hash(self, data): Hashes the key provided, and executes either additive, or one-at-time based on input.

Time Complexity: O(n)

set(self, key, val): Adds a key/value pair to the table. Overwrites the existing value if key is already present.

Time Complexity: O(n)

get(self, key): Returns value associated with key. Raises an error if key is not found.

Time Complexity: O(n)
8 changes: 8 additions & 0 deletions src/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ def bst_right_imbalanced():
from bst import BST
test_bst = BST((1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
return test_bst


@pytest.fixture
def empty_hash():
"""Initialize empty hash table."""
from hash import HashTable
test_hash = HashTable()
return test_hash
58 changes: 58 additions & 0 deletions src/hash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Implementation of a hash table."""


class HashTable(object):
"""HashTable class."""

def __init__(self, size=10, hash_type='additive'):
"""Create new HashTable object."""
self.size = size
self.hash_type = hash_type
self.buckets = []
if hash_type not in ('additive', 'oat'):
raise NameError('Hash funciton unsupported')
for i in range(size):
self.buckets.append([])

def _hash(self, key):
"""Hash string from user on get method."""
if type(key) is not str:
raise TypeError('Key must be a string')
if self.hash_type == 'additive':
hash = 0
for char in key:
hash += ord(char)
print(hash % self.size)
return hash % self.size
if self.hash_type == 'oat':
hash = 0
for char in key:
hash += ord(char)
hash += hash << 10
hash ^= hash >> 6
hash += hash << 3
hash ^= hash >> 11
hash += hash << 15
print(hash % self.size)
return hash % self.size

def set(self, key, val):
"""Add a key/val pair to HashTable."""
idx = self._hash(key)
pair = [key, val]
if not self.buckets[idx]:
self.buckets[idx].append(pair)
else:
for item in self.buckets[idx]:
if item[0] == key:
item[1] = val
self.buckets[idx].append(list(pair))

def get(self, key):
"""Get value at given key."""
idx = self._hash(key)
if self.buckets[idx]:
for item in self.buckets[idx]:
if item[0] == key:
return item[1]
raise KeyError('Key not found')
80 changes: 80 additions & 0 deletions src/test_hash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""Testing for hash table tree."""
import os

import pytest


def test_hash_initialized(empty_hash):
"""Test if hash table initailized with attributes."""
assert empty_hash.size == 10
assert empty_hash.hash_type == 'additive'


def test_hash_initiailized_custom_size():
"""Test if hash table can be initailized with custom size."""
from hash import HashTable
cust_hash = HashTable(size=100)
cust_hash.size == 100


def test_hash_initialized_with_oat():
"""Test if hash table can be initialized using oat hashing function."""
from hash import HashTable
cust_hash = HashTable(hash_type='oat')
cust_hash.hash_type == 'oat'


def test_bad_hash_type_raises_error():
"""Test if ValueError raised if function other than additive or oat is passed."""
from hash import HashTable
with pytest.raises(NameError):
HashTable(hash_type='something')


def test_non_string_passed_in_set_raises_error(empty_hash):
"""Type error raised when non-string passed in set method."""
with pytest.raises(TypeError):
empty_hash.set(897, 'toast')


def test_set_adds_pair(empty_hash):
"""Test if set adds to key/val pair to bucket."""
empty_hash.set('potato', 8)
assert empty_hash.buckets[3] == [['potato', 8]]


def test_get_returns_correct_val(empty_hash):
"""Test if correct val returned for get method."""
empty_hash.set('jim', 39)
assert empty_hash.get('jim') == 39


def test_key_can_be_updated_with_new_val(empty_hash):
"""Test if key's value can be updated."""
empty_hash.set('jim', 39)
empty_hash.set('jim', 83)
assert empty_hash.get('jim') == 83


def test_key_not_found_error_raises(empty_hash):
"""Test if KeyError raised when get used for key not in table."""
empty_hash.set('jane', 34)
empty_hash.set('andy', 32)
with pytest.raises(KeyError):
empty_hash.get('bob')


# def test_dictionary_words():
# """Test built-in unix dictionary of words."""
# from hash import HashTable
# table = HashTable()
# with open('/usr/share/dict/words', 'r') as dictionary:
# all_words = dictionary.read()
# clean_words = all_words.split('\n')
# clean_words = clean_words[:500]
# for i in range(len(clean_words)):
# table.set(clean_words[i], clean_words[i])
# assert table.get('aardvark') == 'aardvark'
# assert table.get('abandon') == 'abandon'
# with pytest.raises(KeyError):
# table.get('house')

0 comments on commit 2e94770

Please sign in to comment.