Need some help on a function - python

Write a function named one_frame that takes one argument seq and performs the tasks specified below. The argument seq is to be a string that contains information for the bases of a DNA sequence.
a → The function searches given DNA string from left to right in multiples of three nucleotides (in a single reading frame).
b → When it hits a start codon ATG it calls get_orf on the slice of the string beginning at that start codon.
c → The ORF returned by get_orf is added to a list of ORFs.
d → The function skips ahead in the DNA string to the point right after the ORF that we just found and starts looking for the next ORF.
e → Steps a through d are repeated until we have traversed the entire DNA string.
The function should return a list of all ORFs it has found.
def one_frame(seq):
start_codon = 'ATG'
list_of_codons = []
y = 0
while y < len(seq):
subORF = seq[y:y + 3]
if start_codon in subORF:
list_of_codons.append(get_orf(seq))
return list_of_codons
else:
y += 3
one_frame('ATGAGATGAACCATGGGGTAA')
The one_frame at the very bottom is a test case. It is supposed to be equal to ['ATGAGA', 'ATGGGG'], however my code only returns the first item in the list.
How could I fix my function to also return the other part of that list?

You have several problems:
You have return list_of_codons inside the loop. So you return as soon as you find the first match and only return that one. Put that at the end of the function, not inside the loop.
You have y += 3 in the else: block. So you won't increment y when you find a matching codon, and you'll be stuck in a loop.
You need to call get_orf() on the slice of the string starting at y, not the whole string (task b).
Task d says you have to skip to the point after the ORF that was returned in task b, not just continue at the next codon.
def one_frame(seq):
start_codon = 'ATG'
list_of_orfs = []
y = 0
while y < len(seq):
subORF = seq[y:y + 3]
if start_codon = subORF:
orf = get_orf(seq[y:])
list_of_orfs.append(orf)
y += len(orf)
else:
y += 3
return list_of_orfs
one_frame('ATGAGATGAACCATGGGGTAA')

You have a number of problems in this code, as identified in the comments. I think this does what you are actually supposed to do:
def one_frame(seq):
start_codon = 'ATG'
list_of_codons = []
y = 0
while y < len(seq):
if seq[y:y+3] == start_codon:
orf = get_orf(seq[y:])
list_of_codons.append(orf)
y += len(orf)
else:
y += 3
return list_of_codons
one_frame('ATGAGATGAACCATGGGGTAA')

Try splitting seq into codons instead:
def one_frame(seq):
shift = 3
codons = [seq[i:i+shift] for i in range(0, len(seq), shift)]
start_codon = "ATG"
orf_list = []
for codon in codons:
if codon == start_codon:
orf_list += [get_orf(codon)]
return orf_list
seq = 'ATGAGATGAACCATGGGGTAA'
one_frame(seq)

Slightly different approach but as I know nothing about DNA sequencing this may not make sense. Here goes anyway:
def one_frame(seq):
start_codon = 'ATG'
list_of_codons = []
offset = 0
while (i := seq[offset:].find(start_codon)) >= 0:
offset += i
list_of_codons.append(get_orf(seq[offset:]))
offset += len(list_of_codons[-1])
return list_of_codons
In this way the find() starts searching from the beginning of the sequence initially but subsequently only from the end of any previous codon

Related

Code for consecutive strings works but can't pass random tests

In this problem, I'm given an array(list) strarr of strings and an integer k. My task is to return the first longest string consisting of k consecutive strings taken in the array. My code passed all the sample tests from CodeWars but can't seem to pass the random tests.
Here's the link to the problem.
I did it in two days. I found the max consecutively combined string first. Here's the code for that.
strarr = []
def longest_consec(strarr, k):
strarr.append('')
length = len(strarr)
cons_list = []
end = k
start = 0
freq = -length/2
final_string = []
largest = max(strarr, key=len, default='')
if k == 1:
return largest
elif 1 < k < length:
while(freq <= 1):
cons_list.append(strarr[start:end])
start += k-1
end += k-1
freq += 1
for index in cons_list:
final_string.append(''.join(index))
return max(final_string, key=len, default='')
else:
return ""
Since that didn't pass all the random tests, I compared the combined k strings on both sides of the single largest string. But, this way, the code doesn't account for the case when the single largest string is in the middle. Please help.
strarr = []
def longest_consec(strarr, k):
strarr.append('')
length = len(strarr)
largest = max(strarr, key=len, default='')
pos = int(strarr.index(largest))
if k == 1:
return largest
elif 1 < k < length:
prev_string = ''.join(strarr[pos+1-k:pos+1])
next_string = ''.join(strarr[pos:pos+k])
if len(prev_string) >= len(next_string):
res = prev_string
else:
res = next_string
return res
else:
return ""
print(longest_consec(["zone", "abigail", "theta", "form", "libe"], 2))
Let's start from the first statement of your function:
if k == 1:
while(p <= 1):
b.append(strarr[j:i])
j += 1
i += 1
p += 1
for w in b:
q.append(''.join(w))
return max(q, key=len)
Here q is finally equal strarr so you can shorten this code to:
if k == 1:
return max(strarr, key=len)
I see that second statement's condition checks if k value is between 1 and length of string array inclusive:
elif k > 1 and k <= 2*a:
...
If you want no errors remove equality symbol, last element of every array has index lesser than its length (equal exactly length of it minus 1).
Ceiling and division is not necessary in a definition, so you can shorten this:
a = ceil(len(strarr)/2)
into this:
a = len(strarr)
then your elif statement may look like below:
elif 1 < k < a: # Same as (k > 1 and k < a)
...
again, I see you want to concatenate (add) the longest string to k next strings using this code:
while(p <= 1):
b.append(strarr[j:i])
j += k-1
i += k-1
p += 1
for w in b:
q.append(''.join(w))
return max(q, key=len)
the more clearer way of doing this:
longest = max(strarr, key=len) # Longest string in array.
index = 0 # Index of the current item.
for string in strarr:
# If current string is equal the longest one ...
if string == longest:
# Join 'k' strings from current index (longest string index).
return ''.join(strarr[index:index + k])
index += 1 # Increase current index.
And the last statement which is:
elif k > 2*a or k<1:
return ""
if all previous statements failed then value is invalid so you can instead write:
return "" # Same as with else.
Now everything should work. I advice you learning the basics (especially lists, strings and slices), and please name your variables wisely so they are more readable.
You can try this as well
this has passed all the test cases on the platform you suggested.
def longest_consec(strarr, k):
i = 0
max_ = ""
res = ""
if (k<=0) or (k>len(strarr)):
return ""
while i<=(len(strarr)-k):
start = "".join(strarr[i:i+k])
max_ = max(max_, start, key=len)
if max_==start:
res=strarr[i:i+k]
i+=1
return max_
#output: ["zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"], 2 -> abigailtheta
#output: ["zones", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"],2 -> zonesabigail

traversing through a list using recursion

So I am new to recursion and I am trying to make a program where you can enter a list and python tests each integer (lets say 9 for example) and sees if the integer following it is doubled. So if I entered a list of 2 4 8 16 32, would return 4, and -5 -10 0 6 12 9 36, would return 2 because -5 followed by -10 is one and 6 followed by 12 is the second. This is the code I have so far. I feel like I am very close. but just a few thing stand in my way. Any help would be great!
L = []
def countDouble(L):
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
print(y[1])
print(y[0])
count = 0
y[0] += y[0]
# unsure of how to multiple y[0] by 2
if y[0]*2 == y[1]:
count += 1
else:
count += 0
#how would I traverse through the rest of the entered list using recursion?
print(count)
countDouble(L)
If you want/need to solve it using recursion, the following will do the trick:
def count_sequential_doubles(li, count=0):
return count_sequential_doubles(li[1:], count + int(li[0] * 2 == li[1])) if len(li) > 1 else count
I would suggest this recursive way:
def countDouble(L):
count = 0
if len(L) == 1:
return count
else:
if int(L[0])*2 == int(L[1]):
count += 1
return count + countDouble(L[1:])
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = countDouble(y)
print(count)
I urge you to read the entire answer, but in case you are not interested in tips, notes and the process of finding the solution, here are two solutions:
solution using recursion (not recommended):
x = input()
y = x.split(' ')
count = 0
def countDouble(i):
if(i+1 == len(y)):
return 'recursion ends here when'
if(int(y[i])*2==int(y[i+1])):
count += 1
countDouble(i+1)
countDouble(0)
print(count)
this solution just imitates a while loop:
solution using a while loop (recommended):
x = input()
y = x.split(' ')
count = 0
i = 0
while(i < len(y) - 1):
if(int(y[i]) * 2 == int(y[i+1])):
count += 1
i += 1
print(count)
Before I continue, here are a few tips and notes: (some of them will only make sense after)
I assume the 14 in your example is a typo
I didn't put the code in a function because it's not needed, but you can change it easily.
In your code, you are passing L as a parameter to the countDouble() function, but you don't use it. if you don't need a parameter don't pass it.
when splitting the input, the values of the list are still strings. so you have to invert them to integers (for instance, you can do that with the int() 'function') before comparing their values - otherwise multiplying by 2 will just repeat the string. for example: '13'*2 is the string '1313'
I don't know why you why you added y[0] to itself in line 9, but based on the code that comes after this would yield incorrect results, you don't need to change the elements in order to get their value multiplied by 2.
notice that in the else block, nothing has changed. adding 0 to the count doesn't change it. so you can remove the else block entirely
While it's possible to solve the problem in recursion, there's something else designed for these kind of problems: loops.
The problem is essentially repeating a simple check for every element of a list.
This is how I would arrive to a solution
so we want to run the following 'code':
if(y[0]*2 == y[1]):
count += 1
if(y[1]*2 == y[2]):
count += 1
if(y[2]*2 == y[3]):
count += 1
...
of course the computer doesn't understand what "..." means, but it gives us an idea to the pattern in the code. now we can do the following:
divide the extended 'code' into similar sections.
identify the variables in the pattern - the values that change between sections
find the starting values of all variables
find a pattern in the changes of each variable
find a breaking point, a condition on one of the variables that tells us we have reached the last repeating section.
here are the steps in this specific problem:
the sections are the if statements
the variables are the indexes of the elements in y we compare
the first index starts at 0 and the second at 1
both indexes increase by one after each if-statement
when the second index is bigger then the last index of y then we already checked all the elements and we can stop
so all is left is to set the needed variables, have a while loop with the breaking condition we found, and in the while loop have the general case of the repeating sections and then the changing of the variables.
so:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
# setting the starting values of the variables
index1 = 0
index2 = 1
# creating a loop with the breaking condition
while(index2 < len(y)):
# the general case of the repeated code:
if(int(y[index1]) * 2 == int(y[index2])):
count += 1
# changing the variables for the next loop
index1 += 1
index2 += 1
print(count)
We see that the index2 is just index1 + 1 at all time. so we can replace it like that:
x = input(f'Enter a list of numbers separated by a space: ')
y = (x.split(' '))
count = 0
index1 = 0
while(index1 + 1 < len(y)):
if(int(y[index1]) * 2 == int(y[index1 + 1])):
count += 1
index1 += 1
print(count)
Note: You can use a for loop similarly to the while loop
So in summary, you can use recursion to solve the problem, but the recursion would just be imitating the process of a loop:
in each call, the breaking condition will be checked, the repeated code would run and the variables/parameters would change.
Hope you find this answer useful :)
Final edit: OP edited his example so my other code didnt apply
Some good questions people are asking, but in the spirit of helping, here's a recursive function that returns the count of all doubles.
def get_doubles_count_with_recursion(a_list, count, previous=None):
while a_list:
try:
first = previous if previous else a_list.pop(0)
next_item = a_list.pop(0)
except IndexError:
return count
if next_item / 2 == first:
count += 1
return get_doubles_count_with_recursion(a_list, count, next_item)
return count
a_list = [1, 3, 5, 10, 11, 14, 28, 56, 88, 116, 232, 464, 500]
doubles = get_doubles_count_with_recursion(a_list, 0)
print(doubles == 5)
Probably could clean it up a bit, but it's a lot easier to read than the other guy's ;)
If I'm reading your question right, you want a count of all pairs where the 2nd item is double the first. (and the 14 in the first list is a typo). In which case a simple function like this should do the job:
#a = [2,4,8,16,32]
a = [-5, -10, 0, 16, 32]
count = 0
for i, x in enumerate(a):
# Stop before the list overflows
if i < len(a) - 1:
# If the next element is double the current one, increment the counter
if a[i+1] == x * 2:
count = count + 1
else:
break
print(count)

Finding longest sequence of consecutive repeats of a substring within a string

My code for the function is really messy and I cannot find why it returns a list of 1's. A solution would obviously be great, but with advice to make the code just better, i'd be happy
def cont_cons_repeats(ADN, STR, pos):
slong = 0
# Find start of sequence
for i in range(len(ADN[pos:])):
if ADN[pos + i:i + len(STR)] == STR:
slong = 1
pos = i + pos
break
if slong == 0:
return 0
# First run
for i in range(len(ADN[pos:])):
i += len(STR) - 1
if ADN[pos + i + 1:pos + i + len(STR)] == STR:
slong += 1
else:
pos = i + pos
break
# Every other run
while True:
pslong = cont_cons_repets(ADN, STR, pos)
if pslong > slong:
slong = pslong
if pslong == 0:
break
return slong
(slong stands for size of longest sequence, pslong for potential slong, and pos for position)
Assuming you pass in pos because you want to ignore the start of the string you're searching up to pos:
def longest_run(text, part, pos):
m = 0
n = 0
while pos < len(text):
if text[pos:pos+len(part)] == part:
n += 1
pos += len(part)
else:
m = max(n, m)
n = 0
pos += 1
return m
You say your function returns a list of 1s, but that doesn't seem to match what your code is doing. Your provided code has some syntax errors, including a misspelled call to your function cont_cons_repets, so it's impossible to say why you're getting that result.
You mentioned in the comments that you thought a recursive solution was required. You could definitely make it work as a recursive function, but in many cases where a recursive function works, you should consider a non-recursive function to save on resources. Recursive functions can be very elegant and easy to read, but remember that any recursive function can also be written as a non-recursive function. It's never required, often more resource-intensive, but sometimes just a very clean and easy to maintain solution.

Alternate letters in a string - code not working

I am trying to make a string alternate between upper and lower case letters. My current code is this:
def skyline (str1):
result = ''
index = 0
for i in str1:
result += str1[index].upper() + str1[index + 1].lower()
index += 2
return result
When I run the above code I get an error saying String index out of range. How can I fix this?
One way using below with join + enumerate:
s = 'asdfghjkl'
''.join(v.upper() if i%2==0 else v.lower() for i, v in enumerate(s))
#'AsDfGhJkL'
This is the way I would rewrite your logic:
from itertools import islice, zip_longest
def skyline(str1):
result = ''
index = 0
for i, j in zip_longest(str1[::2], islice(str1, 1, None, 2), fillvalue=''):
result += i.upper() + j.lower()
return result
res = skyline('hello')
'HeLlO'
Explanation
Use itertools.zip_longest to iterate chunks of your string.
Use itertools.islice to extract every second character without building a separate string.
Now just iterate through your zipped iterable and append as before.
Try for i in range(len(str1)): and substitute index for i in the code. After, you could do
if i % 2 == 0: result += str1[i].upper()
else: result += str1[i].lower()
For every character in your input string, you are incrementing the index by 2. That's why you are going out of bounds.
Try using length of string for that purpose.
you do not check if your index is still in the size of your string.
It would be necessary to add a condition which verifies if the value of i is always smaller than the string and that i% 2 == 0 and that i == 0 to put the 1st character in Upper
with i% 2 == 0 we will apply the upper one letter on two
for i, __ in enumerate(str1):
if i+1 < len(str1) and i % 2 == 0 or i == 0:
result += str1[i].upper() + str1[i + 1].lower()
I tried to modify as minimal as possible in your code, so that you could understand properly. I just added a for loop with step 2 so that you wouldn't end up with index out of range. And for the final character in case of odd length string, I handled separately.
def skyline (str1):
result = ''
length = len(str1)
for index in range(0, length - 1, 2):
result += str1[index].upper() + str1[index + 1].lower()
if length % 2 == 1:
result += str1[length - 1].upper()
return result
You can use the following code:
def myfunc(str1):
result=''
for i in range(0,len(str1)):
if i % 2 == 0:
result += str1[i].upper()
else:
result += str1[i].lower()
return result
in your code you are get 2 word by one time so you should divide your loop by 2 because your loop work by depending your input string so make an variable like peak and equal it to len(your input input) then peak = int(peak/2) it will solve your pr
def func(name):
counter1 = 0
counter2 = 1
string = ''
peak = len(name)
peak = int(peak/2)
for letter in range(1,peak+1):
string += name[counter1].lower() + name[counter2].upper()
counter1 +=2
counter2 +=2
return string

How do I do this "If n is 3, return `1+..1+2+..1+2+3+..`"

Define a function named nested_increasing_additions(n) which receives one positive integer (n) and returns a string as illustrated in the following examples:
If n is 3, the function should return the string:
1+..1+2+..1+2+3+..
If n is 5, the function should return the string:
1+..1+2+..1+2+3+..1+2+3+4+..1+2+3+4+5..+
What I think is, I can make n to a list [1,2,3] and use while loop or for loop to repeat n times. For the first loop it returns 1+.., for the second loop it returns 1+2.. somehow (which i don't know) it stops at 2 which is the same as the repeating time.
I don't know if I'm thinking it right. Need some help and explanations! Thank you!
Consecutive evaluations of these strings results in a sequence of tetrahedral numbers. For example, for input 5, the output evaluates to 35. This is the number of spheres you would need to build a tetrahedron of side length 5.
To see how it relates to the sum in the question, note that the discrete "volume" of the tetrahedron would be equal to the sum of the triangle "slices" from top to bottom.
35 = 1 + 3 + 6 + 10 + 15
= 1 + (1+2) + (1+2+3) + (1+2+3+4) + (1+2+3+4+5)
By a similar argument, the triangular numbers are made up of slices of consecutive integers.
Please excuse the maths, it was difficult (but not impossible) to adapt a closed-form solution into the desired output format.
def tetrahedral(n):
return n*(n+1)*(n+2)//6
def string_generator(n):
x = tetrahedral(n)
n = N = 1
while x > 0:
while n <= N:
yield str(n) + '+'
n += 1
x -= N*(N+1)//2
n = 1
N += 1
yield '..'
def nested_increasing_additions(n):
return ''.join(string_generator(n))
You can build the complete string step by step, and remember at each step what you have added last:
def nested_increasing_additions(n):
complete_string = ""
add_string = ""
for i in range(1,n+1):
add_string += str(i) + "+"
complete_string += add_string + ".."
return complete_string
print(nested_increasing_additions(1))
print(nested_increasing_additions(3))
print(nested_increasing_additions(5))
The output with python3 is:
1+..
1+..1+2+..1+2+3+..
1+..1+2+..1+2+3+..1+2+3+4+..1+2+3+4+5+..
def nested_increasing_additions(n):
l=['']
for i in range(1, n+1):
l.append(l[-1]+str(i)+'+')
return '..'.join(l[1:])
This returns a string without the .. at the end. If you want that, just do return '..'.join(l[1:]) + '..'
you can use something like this.
def nested_increasing_additions(n):
string = ""
for i in range(1,n+1): #1
for j in range(1,i+1): #2
string += str(j)+"+" #4
string += ".." #5
print(string)
here is a printout of nested_increasing_additions(4)
1+..1+2+..1+2+3+..1+2+3+4+..
i think it's self explanatory, nothing complicated.
How's this:
def nested_increasing_additions(n):
string = ""
new_string = ""
dot = ".."
for i in range(1, n+1):
new_string+=('{}+'.format(i))
string = string+new_string+dot
print(string)
return (string)
Output:
nested_increasing_additions(3)
'1+..1+2+..1+2+3+..'
Assuming you did want the ".." at the end of each returned string and that recursion is OK, here's a solution:
def nested_increasing_additions(n):
if n == 1:
return "1+.."
else:
return nested_increasing_additions(n-1) + '%s+..' % '+'.join(str(i) for i in range(1, n+1))
print(nested_increasing_additions(3))
print(nested_increasing_additions(5))
type(nested_increasing_additions(1))
Prints:
1+..1+2+..1+2+3+..
1+..1+2+..1+2+3+..1+2+3+4+..1+2+3+4+5+..
<type 'str'>
Explanation:
The first return and if (true) block ends the recursive call when the passed in argument value reaches 1 via subtraction from the other half.
The second half (else block) calls the next iteration with n subtracted by 1 and the string build of the current iteration (if n!=1).
The complicated looking code '%s+..' % '+'.join(str(i) for i in range(1, n+1)) is just concatenation of a list of numbers generated by the range function, turned into strings and "+.."
range(1, n+1) returns a list of integers starting with 1 until n+1 so range(1,3) yields [1,2]. This is passed to join which places a + between each number.

Categories