Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 21 days ago.
Improve this question
I have a string that needs to be validated that it is of the form of ‘#-#’ where the #s should be unsigned integers. What is the most pythonic way to split this into two integers, lo and hi, possibly including type-checking/validation that lo < hi, unsigned ints, and so on?
I’ve thought about various solutions, but I have varying criteria and it must make sure that # and # are unsigned ints with only the one hyphen in between.
I'm not sure if this is absolutely the most pythong way, but I'd split on the - character and use a list comprehension to generate lo and hi:
[lo, hi] = [int(x) for x in s.split('-')]
You can try something like this:
string = "43-3" #example data
num = string.split("-") #split the string
lo = int(num[0])
hi = int(num[1])
if(lo<hi):
print("ok")
else:
print("ko")
this will work as long your string is exactly as you told us and there are only unsigned ints in the string.
Best I can think of is using a regular expression to match the exact pattern and assert that everything is correct. Note however that doing it this way will crash the program as soon as an invalid input appears, unless you do some extra error handling.
import re
input_strings = [
"123-321",
"92646-278364",
# "12345-123", # error: low > high
# "123.45-98765", # error: not integers
]
def get_num_pair(num_str: str):
m = re.match(r'(\d+)-(\d+)', num_str)
assert m and len(m.groups()) == 2
lo, hi = int(m.group(1)), int(m.group(2))
assert 0 <= lo <= hi
return lo, hi
for input_str in input_strings:
print(get_num_pair(input_str))
Expanding on Mureinik's answer - I'd suggest you do the following:
use a list comprehension to split the list on '-' and turn each bit into ints
carry out validation on the resulting list to ensure it meets your requirements - exactly two elements and the first one is lower
wrap this in a try, except block in case the list comprehension gives an error
wrap that in a function that encapsulates the concept of splitting #-# strings
e.g.
def parse_twoval_str(twoval_str):
try:
vals = [int(s) for s in twoval_str.split("-")]
except ValueError:
raise ValueError("Could not parse input - must be of form '123-234'")
if len(vals) != 2:
raise ValueError("Input must contain two values")
a, b = vals
if a > b:
raise ValueError("First value must be less than second value")
return a, b
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed last year.
Improve this question
Write a function that will accept two parameters: a string and an integer n. Return a new string
where the character at index n has been removed. If the value of n is invalid, return the original
string.
This function will be called into "main" function
Beginning python coder here and I am not the best at understanding how functions work.
my code --> enter image description here
Here you go...
and your code is not correct.
def removeChar(str, pos):
# str[:pos] gives string from index 0 upto pos (excluding pos)
# str[post+1:] gives string from pos + 1 upto end
return str[:pos] + str[pos+1:]
def main():
print(removeChar("Hello", 2))
main()
To remove any character from a String, we have to create a new string since Strings are immutable in Python (unlike lists).
There are several ways to do so -
Using Slicing - This is the most common approach.
s = 'ABCDE'
i = 2
s = s[:i] + s[i+1:]
# s[:i] gives the characters in the string from index 0 to i-1 (excludes index i)
# s[i+1:] gives the characters in the string from index i+1 to end
print(s) # This will print ABDE
Converting to List - We can convert the string to a mutable list of characters. After removing the character at the specified index, we can convert it back to string.
s = 'ABCDE'
i = 2
l = list(s) # Convert to list
del(list[i]) # Deletes the character at index i from the list
s = "".join(l) # Converts the list back to string
print(s) # This will print ABDE
Now, let's discuss about your code :)
def missingChar (str, n):
str = ""
# str is taken as an argument for the function. If it is initialized to "", the purpose of taking it as an input to the function is not served
index = str
value = n
# The above lines are unnecessary
for index in str: # Since, the value of the index at which the character should be removed is already given, a for loop is not needed
index.pop(value) # pop() is a list method... So, it can't be used with strings
return
# Create the main function that will be used throughout the HW
def main():
missingChar("kitten",1) # The function call is perfect :)
# If you want to print the output of the function 'missingChar', store the return value in a variable, and then print it or directly print it by calling the function inside print()
main()
Considering your approach, the following can be done -
def missingChar (s, n):
l = list(s) # Convert to list
l.pop(n) # Use the pop() list method freely :)
s = "".join(l) # Convert the list to string
return s
def main():
result = missingChar("kitten",1)
print(result)
# OR
# print(missingChar("kitten",1))
main()
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Am learning python and one of the questions in our study guide asks to evaluate RNA sequences. I do not get the expected outputs as suggested by the question, I get 17.
Here is the code:
####START FUNCTION
def rna_length(mrna);
start_rna = 'AUG';
end_rna1 = 'UGA';
end_rna2 = 'UAA';
end_rna3 = 'UAG';
if (mrna[0:3]==start_rna) and (mrna [-3:]==end_rna1 or end_rna2 or end_rna3):
length = len(mrna[3:-3])
return length
else: ((mrna[0:3]!=start_rna) or (mrna [-3:]!=end_rna1 or end_rna2 or end_rna3))
return "Not readable RNA code"
####END FUNCTION
A link to a screenshot of the question here
The issue is you using the boolean operator or to compare strings. You can think of the comparisons like this:
(mrna [-3:]==end_rna1 or end_rna2 or end_rna3)
(((mrna [-3:]==end_rna1) or end_rna2) or end_rna3)
Because or is a boolean operator, it needs to work on booleans. You can convert strings to booleans using bool(<str>)
(((mrna [-3:]==end_rna1) or bool(end_rna2)) or bool(end_rna3))
Any string that is not empty (ie. any string that is not "") is "truthy." What that means is that bool(non_empty_str) == True and bool('') == False.
(((mrna [-3:]==end_rna1) or True) or True)
((True) or True)
(True or True)
True
Now, how should you fix it? There are a few approaches to this.
Properly use or.
if (mrna[0:3]==start_rna) and (mrna[-3:]==end_rna1 or mrna[-3:]==end_rna2 or mrna[-3:]==end_rna3):
length = len(mrna[3:-3])
return length
else:
((mrna[0:3]!=start_rna) or (mrna[-3:]!=end_rna1 or mrna[-3:]!=end_rna2 or mrna[-3:]!=end_rna3))
return "Not readable RNA code"
Use a collection. Note that it is standard to use tuples instead of lists whenever you don't want to modify the collection. I used lists here because the brackets look different. You can also use sets for quicker in, but that's overkill for 3.
if mrna[0:3] == start_rna and mrna[-3:] in [end_rna1, end_rna2, end_rna3]:
length = len(mrna[3:-3])
return length
else:
(mrna[0:3] != start_rna or mrna[-3:] not in [end_rna1, end_rna2, end_rna3])
return "Not readable RNA code"
Heck, you can even use the string methods str.startswith and str.endswith.
if mrna.startswith(start_rna) and mrna.endswith([end_rna1, end_rna2, end_rna3]):
length = len(mrna[3:-3])
return length
else:
...
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I need help on how to convert a list to integers, for example
lst = ["1", "2", "3"]
Desired output:
123
I think I explain myself, I do not speak English so I use a translator, I hope it is understood.
You need to do two things: 1. concatenate the elements of the array together into a single string, and 2. convert that string to a number.
You can do #1 with the join string method. Normally, you call join on some other string that you want to put in between the ones you're joining, but since you don't want one of those here, you can just use the empty string:
>>> lst=["1","2","3"]
>>> "".join(lst)
'123'
Since that's still a string, not a numeric value, this is where step 2 comes in. You can convert it to an integer with the int function:
>>> int("".join(lst))
123
Join the strings, then convert to an integer:
int(''.join(lst))
The alternative of converting to integer and then joining is much more complicated, and will drop any leading zeros you have:
from math import floor, log10
result = 0
for x in lst:
n = int(x)
result *= 10**((x and floor(log10(x))) + 1)
result += n
Because of how Python's and operator works, the expression x and ... returns x immediately if it is zero, and the right hand side if not, which is what you want when taking logarithms.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm trying to make a run length decoder that doesn't use 1s. For example a string that could be passed through would be something like ''' A2C3GTA'''. I made what i thought would work and am having trouble finding where I went wrong. I'm a beginner to python so I am sorry for the simple question. Thank you!
def decode(compressed):
decoded= ""
count = 0
for x in compressed :
if x.isdigit():
count += int(x)
y = compressed
decoded += y[int(x)+1] * count
count = 0
else :
decoded += x
print (decoded)
When you find a number-letter pair, you fail to skip the letter after you expand the pair. This is because you used a for loop, which is a more restrictive structure than your logic wants. Instead, try:
idx = 0
while idx < len(compressed):
char = compressed[idx]
if char.isdigit():
# replicate next character
idx += 2
else:
decoded += char
idx += 1
That will take care of your iteration.
Your in appropriate replication, the 22 in your output, this comes from an incorrect reference to the position:
decoded += y[int(x)+1] * count
Here, x is the run length, not the position of the character. If the input were A7B, this ill-formed expression would fault because of an index out of bounds.
In the code I gave you above, simply continue to use idx as the index.
I trust you can finish from here.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
Let's say, the original string is:
a = 'DA115792C339A5E674416AB0559BF5CB8D38E88B1E71F4DFAE896EBD2D13ABB13FFB1DC687DCF0C270A8BF4861D2E6D26E74DC81C18EB53FD5C52AA691A8F16BDA4E1EB8009B00DCD61457E34C438F23EF3D1FD905CF689793CC1E02E1ECB6778A1E2720D416AC432959A8A3B20B43525A856C97E4D404065D1D30ADC74D012B27D00B0029AD3940CB2C9F2AB6C01D430F3A58584C5DB6C98839579AF2A8F90A5D80B5097D547105DF2D9F9485E9F2CCFD6F9ECDDBD562FE09EA81C19B18482BD483AEBAB8481EE208887909DDAE826629538F36E6A50CEECBF3462E9FFBDAC6363F3A9A56F31081EBF28AD0FCF288B0DB8CB44735B9D7E6D193D55C90767E83'
Now, all the instances of 'D6' were replaced with '9F' in above string by doing:
b = a.replace('D6','9F')
b = 'DA115792C339A5E674416AB0559BF5CB8D38E88B1E71F4DFAE896EBD2D13ABB13FFB1DC687DCF0C270A8BF4861D2E6D26E74DC81C18EB53FD5C52AA691A8F16BDA4E1EB8009B00DC9F1457E34C438F23EF3D1FD905CF689793CC1E02E1ECB6778A1E2720D416AC432959A8A3B20B43525A856C97E4D404065D1D30ADC74D012B27D00B0029AD3940CB2C9F2AB6C01D430F3A58584C5DB6C98839579AF2A8F90A5D80B5097D547105DF2D9F9485E9F2CCF9FF9ECDDBD562FE09EA81C19B18482BD483AEBAB8481EE208887909DDAE826629538F36E6A50CEECBF3462E9FFBDAC6363F3A9A56F31081EBF28AD0FCF288B0DB8CB44735B9D7E6D193D55C90767E83'
Now, let's say, we only have the value of b and not a. We need to perform some operations on b to retrieve the original value of a.
Also, we know that the value of 'a' should satisfy a certain mathematical condition.
The mathematical condition is:
number z should be divisible by a (z % a == 0)
z = 55057004365075793824891923502198296150348187500859129529014955509148421282041969078213265169463529503768779794209446773790749529176461595867792548236095966024387560672845152234957439383409540755826755640123124159246487058454615922008741879614211920551517049373314503998980825185719370304183623398662036133862488876163410866971729000216470924616148028986990798495248878127793311548452974671645100371499570058070179424193067736979204502413302335974105838586819414807952974885796840178274113497125765593996690493177955553456655538977929256055738007112424150644005452979891672942537126552535517394691741201589304958975238
We need to leverage this mathematical property of 'a' to restore it from b.
I understand that we cannot use the replace() function on b to get back 'a' because some of the original instances of '9F' might get replaced.
I think we need to perform replace operation in different positions till we satisfy that condition.
For the given string we have:
b.count('9F')
6
So, we would have to replace '9F' with 'D6' in different combinations of positions till we get back 'a' satisfying the mathematical condition, 'C'.
I did something like:
count = b.count('9F')
for i in range(1,count+1):
print "trying: %d" %(i)
tmp = b.replace('9F','D6',i)
num = int(tmp, 16)
if z % num == True:
print num
This seems to be a problem related to permutations and combinations.
You already have 4 instances of 9F in your original string. Those are causing the wierd behaviour
a = 'DA115792C339A5E674416AB0559BF5CB8D38E88B1E71F4DFAE896EBD2D13ABB13FFB1DC687DCF0C270A8BF4861D2E6D26E74DC81C18EB53FD5C52AA691A8F16BDA4E1EB8009B00DCD61457E34C438F23EF3D1FD905CF689793CC1E02E1ECB6778A1E2720D416AC432959A8A3B20B43525A856C97E4D404065D1D30ADC74D012B27D00B0029AD3940CB2C9F2AB6C01D430F3A58584C5DB6C98839579AF2A8F90A5D80B5097D547105DF2D9F9485E9F2CCFD6F9ECDDBD562FE09EA81C19B18482BD483AEBAB8481EE208887909DDAE826629538F36E6A50CEECBF3462E9FFBDAC6363F3A9A56F31081EBF28AD0FCF288B0DB8CB44735B9D7E6D193D55C90767E83'
print(a.count('9F'))
#4
Otherwise the string.replace works perfectly
a = 'hello'
b = a.replace('l','a')
print(b)
#heaao
c = b.replace('a','l')
print(c)
#hello
print( a == c)
#True
Gives you True (Convert l to a, and then a to l)
Possible solution, replace existing 9F to something not present in the string,say XY, then use it in replacing back as well
a = 'DA115792C339A5E674416AB0559BF5CB8D38E88B1E71F4DFAE896EBD2D13ABB13FFB1DC687DCF0C270A8BF4861D2E6D26E74DC81C18EB53FD5C52AA691A8F16BDA4E1EB8009B00DCD61457E34C438F23EF3D1FD905CF689793CC1E02E1ECB6778A1E2720D416AC432959A8A3B20B43525A856C97E4D404065D1D30ADC74D012B27D00B0029AD3940CB2C9F2AB6C01D430F3A58584C5DB6C98839579AF2A8F90A5D80B5097D547105DF2D9F9485E9F2CCFD6F9ECDDBD562FE09EA81C19B18482BD483AEBAB8481EE208887909DDAE826629538F36E6A50CEECBF3462E9FFBDAC6363F3A9A56F31081EBF28AD0FCF288B0DB8CB44735B9D7E6D193D55C90767E83'
#Replace 9F to XY, then D6 to 9F
b = a.replace('9F','XY').replace('D6','9F')
#Replace 9F to D6, then XY to 9F
c = b.replace('9F', 'D6').replace('XY', '9F')
print(a == c)
#True
You won't retrieve your original string back after these two operations, because you probably have "9F" in your original string, too:
test = "D69F"
changed = test.replace("D6", "9F")
print(changed)
# 9F9F
undo_change = changed.replace("9F", "D6")
print(undo_change)
# D6D6
If it don't interfere with your intermediate step you can mask your replacement, e.g. with test.replace("D6", "§9F").