From bbf0fb238cf7adff113b0ba6013790152e1fc33b Mon Sep 17 00:00:00 2001 From: James Warren Date: Fri, 6 Feb 2015 11:30:49 -0800 Subject: [PATCH 1/8] Fix input to list to be value, not node; Adjust tests to reflect input of value, not node --- linked_list.py | 33 +++++++++++----------- test_linked_list.py | 69 ++++++++++++++++----------------------------- 2 files changed, 41 insertions(+), 61 deletions(-) diff --git a/linked_list.py b/linked_list.py index c782093..06917e7 100644 --- a/linked_list.py +++ b/linked_list.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +from __future__ import unicode_literals class Node(object): @@ -7,32 +8,33 @@ def __init__(self, data, nextNode=None): self.nextNode = nextNode def __str__(self): - return self.data + return str(self.data) def __repr__(self): - return self.data + return repr(self.data) class LinkedList(object): def __init__(self, firstNode=None): self.firstNode = firstNode - def insert(self, newNode): - # insert newNode at beginning of list + def insert(self, val): + # insert val at beginning of list + self.newNode = Node(val) if not self.firstNode: - self.firstNode = newNode + self.firstNode = self.newNode else: - newNode.nextNode = self.firstNode - self.firstNode = newNode + self.newNode.nextNode = self.firstNode + self.firstNode = self.newNode def pop(self): # pops first value from list and returns it if self.size() == 0: - return "THE LIST! IT'S EMPTY!!" + raise ValueError("The list is empty") else: obsoleteNode = self.firstNode self.firstNode = self.firstNode.nextNode - return obsoleteNode.data + return obsoleteNode.data.encode('utf-8') def size(self): # returns length of list @@ -46,6 +48,8 @@ def size(self): def search(self, val): # return node containing 'val' in list, if present (else None) currentNode = self.firstNode + if currentNode.data is None: + raise ValueError() while currentNode.data != val: if currentNode.nextNode is None: return None @@ -56,15 +60,12 @@ def search(self, val): def remove(self, node): # remove node from list, wherever it might be if self.size() == 0: - return "THE LIST! IT'S EMPTY!!" + raise ValueError("The list is empty") else: prevNode = None currentNode = self.firstNode - foundNode = False - while not foundNode: - if currentNode == node: - foundNode = True - elif currentNode is None: + while currentNode is not node: + if currentNode is None: raise ValueError() else: prevNode = currentNode @@ -80,6 +81,6 @@ def display(self): display = "(" currentNode = self.firstNode while currentNode is not None: - display += currentNode.data + ", " + display += currentNode.data.encode('utf-8') + ", " currentNode = currentNode.nextNode return display + ")" diff --git a/test_linked_list.py b/test_linked_list.py index b70ecf2..08b5da1 100644 --- a/test_linked_list.py +++ b/test_linked_list.py @@ -3,105 +3,84 @@ import pytest -def test_node_data(): - newNode = Node("Bob") - assert newNode.data == "Bob" - - def test_node_add(): - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) + newList.insert("Bob") assert newList.firstNode.data == "Bob" def test_next_node_none(): - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) + newList.insert("Bob") assert newList.firstNode.nextNode is None def test_add_second_node(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) + newList.insert("Bob") + newList.insert("Joe") assert newList.firstNode.nextNode.data == "Bob" def test_pop(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) + newList.insert("Bob") + newList.insert("Joe") assert newList.pop() == "Joe" def test_pop_size(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) + newList.insert("Bob") + newList.insert("Joe") newList.pop() assert newList.size() == 1 def test_size(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) + newList.insert("Bob") + newList.insert("Joe") assert newList.size() == 2 def test_search_fail(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) + newList.insert("Bob") + newList.insert("Joe") assert newList.search("Fred") is None def test_search_success(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) - assert newList.search("Bob") == bob + newList.insert("Bob") + newList.insert("Joe") + assert newList.search("Bob") is not None def test_remove(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) - newList.remove(bob) + newList.insert("Bob") + newList.insert("Joe") + newList.remove(newList.search("Bob")) assert newList.search("Bob") is None def test_remove_empty(): newList = LinkedList() - assert newList.remove("Bob") == "THE LIST! IT'S EMPTY!!" + with pytest.raises(ValueError): + newList.remove("Bob") def test_pop_empty(): newList = LinkedList() - assert newList.pop() == "THE LIST! IT'S EMPTY!!" + with pytest.raises(ValueError): + newList.pop() def test_remove_fail(): - joe = Node("Joe") - bob = Node("Bob") newList = LinkedList() - newList.insert(bob) - newList.insert(joe) + newList.insert("Bob") + newList.insert("Joe") with pytest.raises(ValueError): newList.remove("Fred") From b3c1a7815e76b49913b9a40bf0a0ae737490d23b Mon Sep 17 00:00:00 2001 From: James Warren Date: Fri, 6 Feb 2015 11:52:37 -0800 Subject: [PATCH 2/8] Remove stack.py and test from branch --- stack.py | 29 ---------------------------- test_stack.py | 52 --------------------------------------------------- 2 files changed, 81 deletions(-) delete mode 100644 stack.py delete mode 100644 test_stack.py diff --git a/stack.py b/stack.py deleted file mode 100644 index 171e056..0000000 --- a/stack.py +++ /dev/null @@ -1,29 +0,0 @@ -class StackItem(object): - def __init__(self, data, next_item=None): - self.data = data - self.next_item = next_item - - def __str__(self): - return self.data - - -class StackFrame(object): - def __init__(self, first_item=None): - self.first_item = first_item - - def push(self, new_item): - # push new_item to beginning of list - if not self.first_item: - self.first_item = new_item - else: - new_item.next_item = self.first_item - self.first_item = new_item - - def pop(self): - # poops first value from list and returns it - if self.first_item is None: - raise ValueError("No items in stack!") - else: - obsolete_item = self.first_item - self.first_item = self.first_item.next_item - return obsolete_item.data diff --git a/test_stack.py b/test_stack.py deleted file mode 100644 index b581f3e..0000000 --- a/test_stack.py +++ /dev/null @@ -1,52 +0,0 @@ -from stack import StackItem -from stack import StackFrame -import pytest - - -def test_item_data(): - # Tests that "Bacon" is returned when calling .data on item - bacon = StackItem("Bacon") - assert bacon.data == "Bacon" - - -def test_create_stack_frame(): - # Tests that an empty stack can be created - new_stack = StackFrame() - assert new_stack - - -def test_stack_push(): - # Tests that "Bacon" is first item when pushed to stack - bacon = StackItem("Bacon") - new_stack = StackFrame() - new_stack.push(bacon) - assert new_stack.first_item.data == "Bacon" - - -def test_stack_push_multi(): - # Tests that we can push multiple items to stack, then get expected results from pop - bacon = StackItem("Bacon") - steak = StackItem("Steak") - grilled_cheese = StackItem("Grilled Cheese") - new_stack = StackFrame() - new_stack.push(bacon) - new_stack.push(steak) - new_stack.push(grilled_cheese) - new_stack.pop() - new_stack.pop() - assert new_stack.first_item.data == "Bacon" - - -def test_stack_pop(): - # Tests that "Bacon" is returned when it is popped from stack - bacon = StackItem("Bacon") - new_stack = StackFrame() - new_stack.push(bacon) - assert new_stack.pop() == "Bacon" - - -def test_empty_stack_pop(): - # Tests that pop() on empty stack returns ValueError - new_stack = StackFrame() - with pytest.raises(ValueError): - new_stack.pop() From 6a3035f7771cea4f5b915fec66c1b430248ff716 Mon Sep 17 00:00:00 2001 From: James Warren Date: Sun, 8 Feb 2015 20:01:08 -0800 Subject: [PATCH 3/8] Initial creation of tests for parenthetics.py --- test_parenthetics.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test_parenthetics.py diff --git a/test_parenthetics.py b/test_parenthetics.py new file mode 100644 index 0000000..d54d687 --- /dev/null +++ b/test_parenthetics.py @@ -0,0 +1,26 @@ +import pytest +from parenthetics import parenthetics + + +def test_single_open(): + assert parenthetics("(") == 1 + + +def test_single_close(): + assert parenthetics(")") == -1 + + +def test_single_balanced(): + assert parenthetics("()") == 0 + + +def test_multi_open_close_1(): + assert parenthetics("(()") == 1 + + +def test_multi_open_close_2(): + assert parenthetics("())") == -1 + + +def test_broken(): + assert parenthetics("))((") == -1 From 1a0e6a29f91abf0af9c6345889eafb590e56c597 Mon Sep 17 00:00:00 2001 From: James Warren Date: Sun, 8 Feb 2015 20:24:20 -0800 Subject: [PATCH 4/8] Outline of parenthetics.py --- parenthetics.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 parenthetics.py diff --git a/parenthetics.py b/parenthetics.py new file mode 100644 index 0000000..7807448 --- /dev/null +++ b/parenthetics.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + + +"""Proper Parenthetics +Return 1 if the string is "open" (there are open parens that are not closed) + +Return 0 if the string is "balanced" (there are an equal number of open and +closed parentheses in the string) + +Return -1 if the string is "broken" (a closing parens has not been proceeded +by one that opens) +""" + + +def f(inp): + count = 0 + for char in inp: + if char == "(": + count += 1 + if char == ")": + count -= 1 + + if count >= 1: + return 1 + elif count <= -1: + return -1 + else: + return 0 + + +print "()" +print f("()") +print +print ")" +print f(")") +print +print "(" +print f("(") +print +print "))((" +print f("))((") +print +print "(())" +print f("(())") From b5b16abee9fb34201c31421a5020710734df9e41 Mon Sep 17 00:00:00 2001 From: James Warren Date: Sun, 8 Feb 2015 20:52:19 -0800 Subject: [PATCH 5/8] Fixed cases with closed parens before open parens --- parenthetics.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/parenthetics.py b/parenthetics.py index 7807448..1b26618 100644 --- a/parenthetics.py +++ b/parenthetics.py @@ -12,13 +12,15 @@ """ -def f(inp): +def parenthetics(inp): count = 0 for char in inp: if char == "(": count += 1 if char == ")": count -= 1 + if count < 0: + return -1 if count >= 1: return 1 @@ -26,19 +28,3 @@ def f(inp): return -1 else: return 0 - - -print "()" -print f("()") -print -print ")" -print f(")") -print -print "(" -print f("(") -print -print "))((" -print f("))((") -print -print "(())" -print f("(())") From c193e65bf3e5534d750c2174bdef41ef4e58a9a3 Mon Sep 17 00:00:00 2001 From: James Warren Date: Sun, 8 Feb 2015 20:54:17 -0800 Subject: [PATCH 6/8] Add additional tests with text --- test_parenthetics.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test_parenthetics.py b/test_parenthetics.py index d54d687..e46bc7f 100644 --- a/test_parenthetics.py +++ b/test_parenthetics.py @@ -24,3 +24,11 @@ def test_multi_open_close_2(): def test_broken(): assert parenthetics("))((") == -1 + + +def test_text(): + assert parenthetics("This is a silly test!") == 0 + + +def test_text_parens(): + assert parenthetics("This is a silly test (but not really that silly)!") == 0 From 4b093e177110f8df100ca40337f5a41c4b6b9084 Mon Sep 17 00:00:00 2001 From: James Warren Date: Sun, 8 Feb 2015 21:11:54 -0800 Subject: [PATCH 7/8] Clean up code; include docstring explaining return values --- parenthetics.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/parenthetics.py b/parenthetics.py index 1b26618..26eb945 100644 --- a/parenthetics.py +++ b/parenthetics.py @@ -1,18 +1,14 @@ #!/usr/bin/env python -"""Proper Parenthetics -Return 1 if the string is "open" (there are open parens that are not closed) - -Return 0 if the string is "balanced" (there are an equal number of open and -closed parentheses in the string) - -Return -1 if the string is "broken" (a closing parens has not been proceeded -by one that opens) -""" +def parenthetics(inp): + """Checks for balanced parenthetic usage in a given input + Returns 1 if the string has open parenthetics that are not properly closed. + Returns 0 if the string is balanced. + Returns -1 if the string has closing parentheses before opening. -def parenthetics(inp): + """ count = 0 for char in inp: if char == "(": @@ -21,10 +17,7 @@ def parenthetics(inp): count -= 1 if count < 0: return -1 - if count >= 1: return 1 - elif count <= -1: - return -1 else: return 0 From 776e02d7e6b7b8daad8f71dfd715646e4b3fb2d5 Mon Sep 17 00:00:00 2001 From: James Warren Date: Mon, 9 Feb 2015 09:33:37 -0800 Subject: [PATCH 8/8] Update README.md for parenthetics.py --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 16f4b85..5cc2692 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,6 @@ We created a linked list method where the list knows about the first element, an We also created a stack where an element can be added to the top of the stack, and popped from the top. But they are not linked and you can only manipulate the top of the stack. +I created a function to test for proper parenthetics in a given input. If there are too many opening parentheses, the function will return 1. If there are closed parentheses before opening parentheses, it will return -1. Otherwise, the function returns 0 to show the input is balanced. + This repository is a collaboration between Jake Anderson and James Warren while attending the Code Fellows Python Development Accelerator in Winter 2015. \ No newline at end of file