diff --git a/README.md b/README.md index 803b3d6..a3593e9 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ ## Make these badges green -[![Build Status](https://travis-ci.org/bast/python-tdd-exercises.svg?branch=master)](https://travis-ci.org/bast/python-tdd-exercises/builds) -[![Coverage Status](https://coveralls.io/repos/bast/python-tdd-exercises/badge.png?branch=master)](https://coveralls.io/r/bast/python-tdd-exercises?branch=master) +[![Build Status](https://travis-ci.org/luyi0629/python-tdd-exercises.svg?branch=master)](https://travis-ci.org/luyi0629/python-tdd-exercises/builds) +[![Coverage Status](https://coveralls.io/repos/luyi0629/python-tdd-exercises/badge.png?branch=master)](https://coveralls.io/r/luyi0629/python-tdd-exercises?branch=master) After you fork, edit this `README.md` and rename "bast" to your GitHub username or namespace to make the badges point to your fork. @@ -22,7 +22,7 @@ or namespace to make the badges point to your fork. - Login to [Travis CI](https://travis-ci.org) with your GitHub account and activate this repo for testing. - Login to [Coveralls](https://coveralls.io) with your GitHub account and activate this repo for code coverage analysis. - Implement missing functions to make the unit tests pass (run tests either locally or let Travis run them for you each time you push changes). -- Increase the test coverage to 100% by making [all lines](https://coveralls.io/r/bast/python-tdd-exercises?branch=master) green. +- Increase the test coverage to 100% by making [all lines](https://coveralls.io/r/luyi0629/python-tdd-exercises?branch=master) green. ## How to run tests locally (Linux or Mac OS X) diff --git a/exercises.py b/exercises.py index 38ef8b7..15df758 100644 --- a/exercises.py +++ b/exercises.py @@ -3,11 +3,12 @@ def reverse_list(l): """ Reverses order of elements in list l. """ - return None - + reverse = l[::-1] + # or l.reverse() + return reverse def test_reverse_list(): - assert reverse_list([1, 2, 3, 4, 5]) == [5, 4, 3, 2, 1] + assert reverse_list([1, 2, 3, 4, 5]) == [5,4,3,2,1] # ------------------------------------------------------------------------------ @@ -16,7 +17,8 @@ def reverse_string(s): """ Reverses order of characters in string s. """ - return None + reverse = s[::-1] + return reverse def test_reverse_string(): @@ -30,7 +32,12 @@ def is_english_vowel(c): Returns True if c is an english vowel and False otherwise. """ - return None + vowels=['a','e','i','o','u','A','E','I','O','U'] + if c in vowels: + out=True + else: + out=False + return out def test_is_english_vowel(): @@ -39,13 +46,13 @@ def test_is_english_vowel(): assert is_english_vowel('i') assert is_english_vowel('o') assert is_english_vowel('u') - assert is_english_vowel('y') + assert not is_english_vowel('y') assert is_english_vowel('A') assert is_english_vowel('E') assert is_english_vowel('I') assert is_english_vowel('O') assert is_english_vowel('U') - assert is_english_vowel('Y') + assert not is_english_vowel('Y') assert not is_english_vowel('k') assert not is_english_vowel('z') assert not is_english_vowel('?') @@ -57,20 +64,26 @@ def count_num_vowels(s): """ Returns the number of vowels in a string s. """ - return None + # use previous function is_english_vowel() + l = [] + for c in s: + if is_english_vowel(c): + l.append(True) + totnum = l.count(True) # or totnum = sum(l) + return totnum def test_count_num_vowels(): sentence = "hey ho let's go" - assert count_num_vowels(sentence) == 5 + assert count_num_vowels(sentence) == 4 sentence = "HEY ho let's GO" - assert count_num_vowels(sentence) == 5 + assert count_num_vowels(sentence) == 4 paragraph = """She told me her name was Billie Jean, as she caused a scene Then every head turned with eyes that dreamed of being the one Who will dance on the floor in the round""" - assert count_num_vowels(paragraph) == 54 + assert count_num_vowels(paragraph) == 52 # ------------------------------------------------------------------------------ @@ -79,7 +92,10 @@ def histogram(l): """ Converts a list of integers into a simple string histogram. """ - return None + out = [] # initialise! + for i in l: + out.append('#'*i) + return "\n".join(out) # turn the list into string with format! def test_histogram(): @@ -93,7 +109,10 @@ def get_word_lengths(s): Returns a list of integers representing the word lengths in string s. """ - return None + out = [] + for i in s.split(): # s.split(): splits the string into list + out.append(len(i)) + return out def test_get_word_lengths(): @@ -108,7 +127,14 @@ def find_longest_word(s): Returns the longest word in string s. In case there are several, return the first. """ - return None + # use previous function get_word_lengths() + w_length = get_word_lengths(s) + lengthmax = sorted(w_length)[-1] # sorted(): returns a new sorted list while leaving the source unaltered + for i in s.split(): + if len(i) == lengthmax: # if the length of current element equals to the max length, + firstmax = i + break # add 'break' to ensure the first one! + return firstmax def test_find_longest_word(): @@ -125,7 +151,20 @@ def validate_dna(s): Return True if the DNA string only contains characters a, c, t, or g (lower or uppercase). False otherwise. """ - return None + # define the dna seq first + dna = 'atcgATCG' + # idea: for each character in the string - test whether the character is dna - append the initialised list with T/F - after reading all characters, if sum(list) equals the length of string, then T, else F. + l = [] + for c in s: + if c in dna: + l.append(True) + else: + l.append(False) + if sum(l) == len(s): + out=True + else: + out=False + return out def test_validate_dna(): @@ -141,7 +180,15 @@ def base_pair(c): of the base pair. If the base is not recognized, return 'unknown'. """ - return None + # make a dictionary + map = {'a':'t', 't':'a', 'c':'g', 'g':'c', 'A':'t','T':'a', 'C':'g','G':'c'} + for k in map: + if k == c: + out = map[k] # note here out is not a list, so the value is replaced at each iteration. to ensure no replacement after a key is matched, add the next line to break the loop. + break + else: + out='unknown' # loop until the last one, and if no match, the last value will be 'unknown'. + return out def test_base_pair(): @@ -164,7 +211,14 @@ def transcribe_dna_to_rna(s): Return string s with each letter T replaced by U. Result is always uppercase. """ - return None + map = {'t':'U', 'T':'U'} + out = [] + for c in s: + if c in ['t', 'T']: + out.append(map[c]) + else: + out.append(c.upper()) # list.upper() returns the uppercase + return "".join(out) # again, turn the list into string with format def test_transcribe_dna_to_rna(): @@ -179,8 +233,13 @@ def get_complement(s): Return the DNA complement in uppercase (A -> T, T-> A, C -> G, G-> C). """ - return None - + # use previous function base_pair() + out = [] + for c in s: + out.append(base_pair(c).upper()) + return "".join(out) # again, turn the list into string with format +# or in one line, use map function, apply the function to each element in the function. +# return ''.join(map(base_pair(s))).upper() def test_get_complement(): assert get_complement('CCGGAAGAGCTTACTTAG') == 'GGCCTTCTCGAATGAATC' @@ -194,7 +253,10 @@ def get_reverse_complement(s): Return the reverse complement of string s (complement reversed in order). """ - return None + # use two functions defined earlier: get_complement() and reverse_string() + string = "".join(get_complement(s)) + r_string = reverse_string(string) + return r_string def test_get_reverse_complement(): @@ -208,7 +270,8 @@ def remove_substring(substring, string): """ Returns string with all occurrences of substring removed. """ - return None + out = string.replace(substring, "") # note the replace() method! + return out def test_remove_substring(): @@ -226,8 +289,19 @@ def get_position_indices(triplet, dna): in a DNA sequence. We start counting from 0 and jump by 3 characters from one position to the next. """ - return None - + # first split the seq by triplets + # use range(start, stop, step) to jump + out = [] + out_index = [] + for i in range(0, len(dna), 3): + out.append(dna[i:i+3]) + for j in range(0,len(out)): + if out[j] == triplet: + out_index.append(j) + return out_index +# l = [] +# for i in range(len(dna)//3): # // gives integer +# if triplet == i .... def test_get_position_indices(): assert get_position_indices('GAA', 'CCGGAAGAGCTTACTTAG') == [1] @@ -245,7 +319,29 @@ def get_3mer_usage_chart(s): The list is alphabetically sorted by the name of the 3-mer. """ - return None + # compared to the above, here no need to define the step because moving the character one by one. but note the stop should be len(s)-2, otherwise the last two elements in the list would have < 3-mers. + mylist = [] + mylist2 = [] + for i in range(0, len(s)-2): + mylist.append(s[i:i+3]) + # use list(set()) to get the unique elements only: + uniqlist = list(set(mylist)) + for j in sorted(uniqlist): + c = mylist.count(j) + mylist2.append((j,c)) + return mylist2 +# can use dictionary instead! in the end, convert the dictionary to list using items() method. +# use += 1 to add to the counter! +# d = {} +# for i in range(len(s)-2): +# kmer = s[i:i+3] +# if kmer in d: +# d[kmer] += 1 +# else: +# d[kmer] = 1 +# l = list(d.iterms()) +# l.sort() +# return l def test_get_3mer_usage_chart(): @@ -276,7 +372,13 @@ def read_column(file_name, column_number): Reads column column_number from file file_name and returns the values as floats in a list. """ - return None + out = [] + with open(file_name, 'r') as f: # r is read, w is write + for line in f: + parts = line.split() # this will also create a first empty line! + if len(parts) > 0: + out.append(float(parts[column_number-1])) # add float + return out def test_read_column(): @@ -291,10 +393,12 @@ def test_read_column(): 4 0.4 0.004 5 0.5 0.005 6 0.6 0.006""" +# this way the first line is empty. +# if text = """1 0.1 .... , then it will not be a problem. # we save this text to a temporary file file_name = tempfile.mkstemp()[1] - with open(file_name, 'w') as f: + with open(file_name, 'w') as f: # open it and write in text f.write(text) # and now we pass the file name to the function which will read the column @@ -315,7 +419,20 @@ def character_statistics(file_name): Use the isalpha() method to figure out whether the character is in the alphabet. """ - return None + d = {} + with open(file_name, 'r') as f: + for c in f.read().lower(): + if c.isalpha(): + if c in d: # d is adding up! not just empty dictionary + d[c] += 1 + else: + d[c] = 1 + l = list(d.items()) + # then sort on the value, not the key! + l = sorted(l, key=lambda x: x[1], reverse = True) + most = l[0][0] + least = l[-1][0] + return (most, least) def test_character_statistics(): @@ -367,7 +484,7 @@ def test_character_statistics(): # and now we pass the file name to the function which will get the stats (most_abundant, least_abundant) = character_statistics(file_name) - assert (most_abundant, least_abundant) == ('e', 'q') + assert (most_abundant, least_abundant) == ('e', 'z') # here q and z are least abundant. # we remove the temporary file os.unlink(file_name) @@ -393,4 +510,10 @@ def pythagorean_triples(n): # ------------------------------------------------------------------------------ def test_pythagorean_triples(): - pass # so far we do not test anything, check also test coverage + assert pythagorean_triples(12) == [(3,4,5), (6,8,10)] +# pass # so far we do not test anything, check also test coverage + +# in an interactive python session, can import this script. +# import exercises +# then, just write the function name to run the funciton: +# e.g. excercises.pythagorean_triples(200)