From dd6107f35c0e47cc93f46dc78d549c8934c7d4e8 Mon Sep 17 00:00:00 2001 From: chai Date: Sun, 10 Dec 2017 18:49:07 -0800 Subject: [PATCH 1/4] update hash tabel --- src/hash_table.py | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/hash_table.py diff --git a/src/hash_table.py b/src/hash_table.py new file mode 100644 index 0000000..dca729e --- /dev/null +++ b/src/hash_table.py @@ -0,0 +1,62 @@ +"""Hash table.""" + + +def naive_hash(word, buckets): + """Hash for strings.""" + hash_val = 0 + for letter in word: + hash_val += ord(letter) + return hash_val % buckets + + +def horner_hash(word, buckets): + """Using horner's rule for hashing key.""" + constant = 37 + result = 0 + for letter in word: + result = result * constant + ord(letter) + return result % buckets + + +class HashTable(object): + """Hash table class.""" + + def __init__(self, size=10, hash_func=naive_hash): + """Initialize a new hashtable.""" + self.hash_func = hash_func + self._size = size + self._buckets = [[] for x in range(self._size)] + + def get(self, key): + """Return the value of the key given.""" + hash_key = self._hash(key) + if self._buckets[hash_key] == []: + return 'This key does not exist.' + else: + for idx, item in enumerate(self._buckets[hash_key]): + if item[0] == key: + return self._buckets[hash_key][idx][1] + else: + return 'This key does not exist.' + + def set(self, key, val): + """Pass a value into the table for storage.""" + if not isinstance(key, str): + raise TypeError('You must enter a word as a key.') + hash_key = self._hash(key) + if self._buckets[hash_key] == []: + self._buckets[hash_key].append((key, val)) + else: + for idx, item in enumerate(self._buckets[hash_key]): + if item[0] == key: + gone = item[1] + self._buckets[hash_key][idx] = (key, val) + return 'Your data {} has been updated to {} at key {}.'\ + .format(gone, val, key) + else: + self._buckets[hash_key].append((key, val)) + + def _hash(self, key): + """Hash the data on set.""" + buckets = self._size + return self.hash_func(key, buckets) From c0b5c695720a0453e9bba34a529965d938b550af Mon Sep 17 00:00:00 2001 From: chai Date: Sun, 10 Dec 2017 19:07:36 -0800 Subject: [PATCH 2/4] Wrote test for hash-table --- src/priorityq.py | 42 -------------- src/test_hash_table.py | 56 +++++++++++++++++++ src/test_priorityq.py | 122 ----------------------------------------- 3 files changed, 56 insertions(+), 164 deletions(-) delete mode 100644 src/priorityq.py create mode 100644 src/test_hash_table.py delete mode 100644 src/test_priorityq.py diff --git a/src/priorityq.py b/src/priorityq.py deleted file mode 100644 index 04fa8a3..0000000 --- a/src/priorityq.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Create a priority queue instance.""" - - -class Priorityq(object): - """Create a que with priority attributes for each value.""" - - def __init__(self): - """Initialize a priority queue instance.""" - self._que = {} - self._highest = 0 - self._lowest = 0 - - def insert(self, val, priority=0): - """Insert a new value into the queue.""" - if priority <= self._highest: - self._highest = priority - if priority >= self._lowest: - self._lowest = priority - if priority in self._que: - self._que[priority].append(val) - else: - self._que[priority] = [val] - - def pop(self): - """Remove the highest prioty value from queue.""" - if len(self._que) == 0: - raise IndexError('There are no value to pop.') - else: - val = self._que[self._highest].pop(0) - if self._que[self._highest] == []: - self._que.pop(self._highest) - if len(self._que) == 0: - self._highest = 0 - self._lowest = 0 - else: - high = min(self._que) - self._highest = high - return val - - def peek(self): - """View the hightest priority item.""" - return self._que[self._highest][0] diff --git a/src/test_hash_table.py b/src/test_hash_table.py new file mode 100644 index 0000000..1855f80 --- /dev/null +++ b/src/test_hash_table.py @@ -0,0 +1,56 @@ +"""Test hash table.""" + +import pytest + + +def test_naive_hash_returns_int_between_zero_and_input(): + """Test navie hash returns an int between zero and len buckets.""" + from hash_table import naive_hash + word = 'Testing' + length = 100 + assert naive_hash(word, length) < 100 + assert naive_hash(word, length) >= 0 + + +def test_naive_get_if_item_not_in_table_returns_error_message(): + """Test naive get if item not in table returns error message.""" + from hash_table import HashTable + table = HashTable() + assert table.get('Testing') == 'This key does not exist.' + + +def test_naive_get_item_not_in_table_returns_error_if_other_item_has_key(): + """Test naive get if item not in table returns error message.""" + from hash_table import HashTable + table = HashTable() + table.set('Bob', 'Ross') + assert table.get('Painting') == 'This key does not exist.' + + +def test_hashtable_raises_type_error_if_not_input_string(): + """Test hashtable raises typeerror if input is not string.""" + from hash_table import HashTable + table = HashTable() + with pytest.raises(TypeError): + table.set(5, 'Test') + + +def test_horners_hashtable_set_and_get_one_word(): + """Test horners hashtable set and gets one word.""" + from hash_table import HashTable, horner_hash + table = HashTable(100, horner_hash) + table.set('Bob', 'Ross') + bob = table.get('Bob') + assert bob == 'Ross' + + +def test_horners_input_same_key_twice_resets_val(): + """Test horners input same key twice resets vala at key.""" + from hash_table import HashTable, horner_hash + table = HashTable(10, horner_hash) + table.set('Ross', 'Ross') + assert table.set('Ross', 'Bob') == ('Your data Ross has been ' + 'updated to Bob at key Ross.') + ross = table.get('Ross') + assert table.get('Ross') == 'Bob' + diff --git a/src/test_priorityq.py b/src/test_priorityq.py deleted file mode 100644 index 8ff64fb..0000000 --- a/src/test_priorityq.py +++ /dev/null @@ -1,122 +0,0 @@ -"""Test priorityq.py.""" -import pytest - - -def test_priorityq_iinitialize_empty_que(pq): - """Test initialize an empty pq.""" - assert pq - - -def test_priorityq_insert_one_val_w_priority(pq): - """Test insert one value to pq with priority.""" - pq.insert('hi', 0) - assert pq._highest == 0 - - -def test_insert_n_values_returns_n_length(pq): - """Test that the number of values inserted is the que's length.""" - for i in range(20): - pq.insert(i) - total_length = 0 - for key in pq._que: - total_length += len(pq._que[key]) - assert total_length == 20 - - -def test_priorityq_insert_with_many_priority_returns_higest(pq): - """Test ipriorityq insert with many priority returns higest pirority.""" - pq.insert('hi', -10) - pq.insert('one', 1) - pq.insert('four', 4) - pq.insert('eight', 8) - assert pq._highest == -10 - - -def test_priorityq_insert_with_many_priority_returns_lowest(pq): - """Test ipriorityq insert with many priority returns lowest pirority.""" - pq.insert('hi', -10) - pq.insert('one', 1) - pq.insert('four', 4) - pq.insert('eight', 8) - assert pq._lowest == 8 - - -def test_priorityq_insert_with_same_priority_returns_list_of_val(pq): - """Test if inserted with same priority returns list of val in pirority.""" - pq.insert('hi', -10) - pq.insert('one', -10) - pq.insert('four', 4) - pq.insert('eight', 4) - assert pq._que[-10] == ['hi', 'one'] - - -def test_if_pop_raises_indexerror_on_empty_prorityq(pq): - """Test if pop reises indexerroe.""" - with pytest.raises(IndexError): - pq.pop() - - -def test_priorityq_pop_function_pops(pq): - """Test ipriorityq if it pops a val.""" - pq.insert('hi', -10) - pq.insert('one', 1) - pq.pop() - pq.pop() - assert pq._que == {} - - -def test_priorityq_pop_function_returns_val(pq): - """Test ipriorityq if it pops and returns the right val.""" - pq.insert('hi', -10) - pq.insert('one', 1) - assert pq.pop() == 'hi' - - -def test_pop_if_more_poped_then_inserted_raises_error(pq): - """Test if inserted with same priority returns list of val in pirority.""" - pq.insert('hi', -10) - pq.insert('one', -10) - pq.insert('four', 4) - pq.pop() - pq.pop() - pq.pop() - with pytest.raises(IndexError): - pq.pop() - - -def test_pop_if_returns_in_prioety_order(pq): - """Test if inserted with priority returns in priority order.""" - pq.insert('hi', -10) - pq.insert('one', -1) - pq.insert('four', 4) - pop1 = pq.pop() - pop2 = pq.pop() - pop3 = pq.pop() - assert pop1 == 'hi' - assert pop2 == 'one' - assert pop3 == 'four' - - -def test_pop_if_returns_in_prioety_order_pop_in_and_out(pq): - """Test if inserted val with priority returns in priority order.""" - pq.insert('hi', -10) - pq.insert('four', 4) - pq.insert('one', -1) - pop1 = pq.pop() - pop2 = pq.pop() - pq.insert('first', -20) - pop3 = pq.pop() - pq.insert('last', 20) - pop4 = pq.pop() - assert pop1 == 'hi' - assert pop2 == 'one' - assert pop3 == 'first' - assert pop4 == 'four' - - -def test_peek_returns_the_higest_priority_val(pq): - """Test if peek returns the val in line to be poped.""" - pq.insert('hi', -10) - pq.insert('one', 1) - pq.insert('four', 4) - assert pq.peek() == 'hi' From ecc3e0057497477b79177c79e45b758554782ce2 Mon Sep 17 00:00:00 2001 From: chai Date: Sun, 10 Dec 2017 19:19:46 -0800 Subject: [PATCH 3/4] Updated ReadMe --- .travis.yml | 16 ++++++++++++++++ README.md | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1159858 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,16 @@ +language: python +python: + - "2.7" + - "3.6" +notifications: + email: false + +install: + - pip install tox-travis + - pip install coveralls + +script: + - tox + +after_success: + - coveralls \ No newline at end of file diff --git a/README.md b/README.md index 87c500a..db7f3a1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,20 @@ # data-structures -Data-Structures + +### Hash Table + +``` +Using a naive hash and Horner's Rule, HashTable() will store based on the supplied key, which must be a string. By default, HashTable() uses the naive hash method, but can be changed on initialization. + +To create an instance if the hash table, HashTable(), from python: + +new = HashTable() *you may initiate the table with any size, must be integer, as the first arguement in the function. You may also pass in an alternative hashing method. A naive hash will be used my defaul, but you may also choose `horner_hash` as the second arguement on initialization, or any hashing function you choose to import. For example: HashTable(100000, horner_hash).* + +HashTable() contains the following methods: +* _set(key, val) (O(n))_ - sets a value at a given key (must me string) in the table, if key already has value it will be set to new value. +* _get(key) (0(n))_ - retrieve the value of the item with the given key. +* _ _hash(key) (O(n))_ - hashes key and returns an integer between 0 and the size of the table. + +To access any contained methods: +new.set(key, val) +new.get(key) +``` \ No newline at end of file From 7884610303955b7836cf2653414c75e29ce0a02e Mon Sep 17 00:00:00 2001 From: chai Date: Sun, 10 Dec 2017 19:59:33 -0800 Subject: [PATCH 4/4] Added test --- README.md | 17 ++++------- src/bubble_sort.py | 53 +++++++++++++++++++++++++++++++++++ src/hash_table.py | 62 ----------------------------------------- src/test_bubble_sort.py | 39 ++++++++++++++++++++++++++ src/test_hash_table.py | 56 ------------------------------------- 5 files changed, 97 insertions(+), 130 deletions(-) create mode 100644 src/bubble_sort.py delete mode 100644 src/hash_table.py create mode 100644 src/test_bubble_sort.py delete mode 100644 src/test_hash_table.py diff --git a/README.md b/README.md index db7f3a1..56d49fd 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,13 @@ # data-structures -### Hash Table +### Bubble Sort ``` -Using a naive hash and Horner's Rule, HashTable() will store based on the supplied key, which must be a string. By default, HashTable() uses the naive hash method, but can be changed on initialization. +Bubble sort takes in a list of numbers and uses a bubble sort method to return a sorted list. -To create an instance if the hash table, HashTable(), from python: +To use bubble_sort, from bubble_sort import bubble_sort. +Pass in a list of numbers bubble_sort(list). -new = HashTable() *you may initiate the table with any size, must be integer, as the first arguement in the function. You may also pass in an alternative hashing method. A naive hash will be used my defaul, but you may also choose `horner_hash` as the second arguement on initialization, or any hashing function you choose to import. For example: HashTable(100000, horner_hash).* +* _bubble_sort(list) (O(n^2))_ -HashTable() contains the following methods: -* _set(key, val) (O(n))_ - sets a value at a given key (must me string) in the table, if key already has value it will be set to new value. -* _get(key) (0(n))_ - retrieve the value of the item with the given key. -* _ _hash(key) (O(n))_ - hashes key and returns an integer between 0 and the size of the table. - -To access any contained methods: -new.set(key, val) -new.get(key) ``` \ No newline at end of file diff --git a/src/bubble_sort.py b/src/bubble_sort.py new file mode 100644 index 0000000..b4e09d2 --- /dev/null +++ b/src/bubble_sort.py @@ -0,0 +1,53 @@ +"""Function to run a bubble sort on a given list of numbers.""" +import time +from random import randint + + +def bubble_sort(list): + """Bubble sort function.""" + global looped + looped = 1 + for i in range(len(list) - looped): + if list[i] > list[i + 1]: + list[i], list[i + 1] = list[i + 1], list[i] + else: + continue # pragma: no cover + looped += 1 + bubble_sort(list) + return list + +if __name__ == '__main__': + + short_list = [randint(1, 50) for _ in range(10)] + print('\nCASE 1: A small list to be sorted:\n', short_list) + short_list = timeit.timeit("bubble_sort(short_list)", setup="from __main__ import short_list, bubble_sort") + print('Short list time: ', short_list) + + print('\nCASE 2: A list of 100 numbers:\n') + hundred = [randint(1, 100000) for x in range(100)] + start_hundred = time.time() + solve_hundred = (time.time() - start_hundred) * 1000 + print(bubble_sort(hundred)) + print('\nSorted using bubble_sort() in {} seconds.'.format(solve_hundred)) + + print('\nCASE 3: A list of 1,000 random numbers:') + thousand = [randint(1, 100000) for x in range(1000)] + start_thousand = time.time() + solve_thousand = (time.time() - start_thousand) * 1000 + print(thousand) + print(bubble_sort(thousand)) + print('\nSorted using bubble_sort() {} seconds'.format(solve_thousand)) + + print('\nCASE 4: A list of 10,000 numbers (not shown):\n') + ten = [randint(1, 100000) for x in range(10000)] + start_ten = time.time() + solve_ten = (time.time() - start_ten) * 1000 + print(bubble_sort(ten)) + print('\nSorted using bubble_sort() in {} seconds.'.format(solve_ten)) + + print('\nCASE 5: A list of 100,000 words:\n') + mil = [randint(1, 100000) for x in range(100000)] + start_mil = time.time() + solve_mil = (time.time() - start_mil) * 1000 + print(bubble_sort(mil)) + print('\nSorted using bubble_sort() in {} seconds.'.format(solve_mil)) diff --git a/src/hash_table.py b/src/hash_table.py deleted file mode 100644 index dca729e..0000000 --- a/src/hash_table.py +++ /dev/null @@ -1,62 +0,0 @@ -"""Hash table.""" - - -def naive_hash(word, buckets): - """Hash for strings.""" - hash_val = 0 - for letter in word: - hash_val += ord(letter) - return hash_val % buckets - - -def horner_hash(word, buckets): - """Using horner's rule for hashing key.""" - constant = 37 - result = 0 - for letter in word: - result = result * constant + ord(letter) - return result % buckets - - -class HashTable(object): - """Hash table class.""" - - def __init__(self, size=10, hash_func=naive_hash): - """Initialize a new hashtable.""" - self.hash_func = hash_func - self._size = size - self._buckets = [[] for x in range(self._size)] - - def get(self, key): - """Return the value of the key given.""" - hash_key = self._hash(key) - if self._buckets[hash_key] == []: - return 'This key does not exist.' - else: - for idx, item in enumerate(self._buckets[hash_key]): - if item[0] == key: - return self._buckets[hash_key][idx][1] - else: - return 'This key does not exist.' - - def set(self, key, val): - """Pass a value into the table for storage.""" - if not isinstance(key, str): - raise TypeError('You must enter a word as a key.') - hash_key = self._hash(key) - if self._buckets[hash_key] == []: - self._buckets[hash_key].append((key, val)) - else: - for idx, item in enumerate(self._buckets[hash_key]): - if item[0] == key: - gone = item[1] - self._buckets[hash_key][idx] = (key, val) - return 'Your data {} has been updated to {} at key {}.'\ - .format(gone, val, key) - else: - self._buckets[hash_key].append((key, val)) - - def _hash(self, key): - """Hash the data on set.""" - buckets = self._size - return self.hash_func(key, buckets) diff --git a/src/test_bubble_sort.py b/src/test_bubble_sort.py new file mode 100644 index 0000000..3262d7c --- /dev/null +++ b/src/test_bubble_sort.py @@ -0,0 +1,39 @@ +"""Test bubble sort.""" + +from bubble_sort import bubble_sort + + +def test_bubble_sort_on_empty_list_returns_empty(): + """Test bubble sort on empty list retruns empty list.""" + test = [] + assert bubble_sort(test) == [] + + +def test_bubble_sort_on_list_of_three(): + """Test bubble sort on list of three retuned sorted.""" + test = [6, 8, 2] + assert bubble_sort(test) == [2, 6, 8] + + +def test_bubble_sort_with_sorted_list_no_change(): + """Test bubble sort with sorted list returns no change.""" + test = [1, 2, 3, 4, 5, 6, 7, 8, 9] + assert bubble_sort(test) == [1, 2, 3, 4, 5, 6, 7, 8, 9] + + +def test_bubble_sort_on_reverse_sort_returns_sorted(): + """Test bubble sort with reverse sort returns sorted.""" + test = [9, 8, 7, 6, 5, 4, 3, 2, 1] + assert bubble_sort(test) == [1, 2, 3, 4, 5, 6, 7, 8, 9] + + +def test_bubble_sort_of_all_nums_same_returns_same(): + """Test bubble sort if all nums same returns the same.""" + test = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + assert bubble_sort(test) == test + + +def test_bubble_sort_with_one_variant_returns_sorted(): + """Test bubble sort with one variant returns sorted.""" + test = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0] + assert bubble_sort(test) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 1] \ No newline at end of file diff --git a/src/test_hash_table.py b/src/test_hash_table.py deleted file mode 100644 index 1855f80..0000000 --- a/src/test_hash_table.py +++ /dev/null @@ -1,56 +0,0 @@ -"""Test hash table.""" - -import pytest - - -def test_naive_hash_returns_int_between_zero_and_input(): - """Test navie hash returns an int between zero and len buckets.""" - from hash_table import naive_hash - word = 'Testing' - length = 100 - assert naive_hash(word, length) < 100 - assert naive_hash(word, length) >= 0 - - -def test_naive_get_if_item_not_in_table_returns_error_message(): - """Test naive get if item not in table returns error message.""" - from hash_table import HashTable - table = HashTable() - assert table.get('Testing') == 'This key does not exist.' - - -def test_naive_get_item_not_in_table_returns_error_if_other_item_has_key(): - """Test naive get if item not in table returns error message.""" - from hash_table import HashTable - table = HashTable() - table.set('Bob', 'Ross') - assert table.get('Painting') == 'This key does not exist.' - - -def test_hashtable_raises_type_error_if_not_input_string(): - """Test hashtable raises typeerror if input is not string.""" - from hash_table import HashTable - table = HashTable() - with pytest.raises(TypeError): - table.set(5, 'Test') - - -def test_horners_hashtable_set_and_get_one_word(): - """Test horners hashtable set and gets one word.""" - from hash_table import HashTable, horner_hash - table = HashTable(100, horner_hash) - table.set('Bob', 'Ross') - bob = table.get('Bob') - assert bob == 'Ross' - - -def test_horners_input_same_key_twice_resets_val(): - """Test horners input same key twice resets vala at key.""" - from hash_table import HashTable, horner_hash - table = HashTable(10, horner_hash) - table.set('Ross', 'Ross') - assert table.set('Ross', 'Bob') == ('Your data Ross has been ' - 'updated to Bob at key Ross.') - ross = table.get('Ross') - assert table.get('Ross') == 'Bob' -