I want to write a summation function, but can't figure out how I would parse the bottom expression and right expression.
def summation(count: int, bottom_var: str, espression: str):
out = 0
# parse bottom_var into a variable and it's value
value = ···
var_name = ···
expression.replace(var_name, value)
···
I want you to be able to use the inputs the same way as in normal sigma notation, as in bottom_var is 'n=13', not '13'.
You enter an assignment for bottom_var, and an expression using the variable defined in bottom_var in expression.
Example:
summation(4, 'x=1', 'x+1')
(would return 14, as 2+3+4+5=14)
First, parse the bottom_var to get the symbol and starting value:
var, value = bottom_var.split('=')
var = var.strip()
value = eval(value)
Using split we get the two parts of the equal sign easily. Using strip we even allow any number of spaces, like x = 1.
Then, we want to create a loop from the starting value to count:
for i in range(value, count+1):
...
Lastly, we want to use the loop to sum the expression when each time the symbol is replaced with the current iteration's value. All in all:
def summation(count: int, bottom_var: str, expression: str):
var, value = bottom_var.split('=')
var = var.strip()
value = eval(value)
res = 0
for i in range(value, count+1):
res += eval(expression.replace(var, str(i)))
return res
For example:
>>> summation(4, 'x=1', 'x+1')
14
Proposing the code in this answer, I feel the need to ask you to read about Why is using 'eval' a bad practice? and please make sure that it is OK for your application. Notice that depending on the context of the use of your code, using eval can be quite dangerous and lead to bad outcomes.
This is how i did it:
def summation(count,bottom_var,expression):
begin = False
x = ""
v = ""
for char in bottom_var:
if begin:
x += char
if char == "=":
begin = True
if begin == False:
v += char
x = int(x)
expression = expression.replace(v,str("x"))
print(expression)
for n in range(count):
x = eval(expression)
summation(4,"d=152",'d+145*2')
There are some built-in function in python which execute code from text or str which are exec() and eval() function.
for example :
>>> exec('n=13')
>>> print(n)
13
>>> eval('n+1')
14
you can use this in your code.
Related
I have to write a function that receives a string and returns that string with the characters between "*" in uppercase, for example given that string: “I want *this text* to be uppercase”, it returns : “I want THIS TEXT to be uppercase”.
Here is the code that I have written:
l = []
def func(s):
inside = False
for i in s:
if i == "*" and not inside:
inside = True
while inside:
if i == "*":
inside = False
else:
i.upper()
l.append(i)
print(s)
When I run the program it prints out the text without any change.
What am I doing wrong?
By splitting the string at the character * then the uppercase entry is the odd one, then joining together. It is supposed that there are always an even number of * so it should be considered a kind of reserved character.
s = "I want *this text* to be uppercase and *this* as well"
print(' '.join((j.upper() if i%2!=0 else j for i, j in enumerate(s.split('*')))))
Output
I want THIS TEXT to be uppercase and THIS as well
First, this function isn't doing anything to s, so print(s) will print whatever was input, unchanged.
Second, the while inside loop needs to be outside of that if statement - right now, it's only accessed when i is an asterisk. Decrease that whole block's indent by one, and change while inside to if inside - that way, that code is executed for all values of i when inside is true.
Next, you need a way to signal when a second asterisk is reached, or a third, and so on. How about instead of assigning inside to True if i is an asterisk and inside is False, you swap the value of inside every time an asterisk is reached?
if i == '*':
inside = not inside
This negates any need to mess with changing inside in the second part of your code - it puts all the determining "am I inside/am I outside" logic in one place.
Next, you've declared a list l outside the scope of the function, and it looks like you want to add the edited characters to it so the answer you want is in that list in the end. But you want your answer in a string, not a list, and it's usually bad practice to declare a list in global scope and then edit it during a function call (if you call the function more than once, the list will get messy!). Declare an empty string l = '' at the beginning of the function, and then instead of appending characters to it, you can add them using the += operator.
You also need to make sure you're adding the uppercase version, l += i.upper() or the regular version, l += i, depending on whether or not inside is true. You can put all the code after the if i == '*' line in an else statement to catch all cases that i isn't an asterisk.
Putting it all together, your function can look something like this:
def func(s):
l = '' # the string that will be returned (the result of the function)
inside = False
for i in s:
if i == "*": # flip value of inside whenever you see an asterisk
inside = not inside
else: # otherwise, add i to the result
if inside:
l += i.upper() # uppercase if between two asterisks
else:
l += i # unchanged if not
return l # and return the modified string
Then, to test the function:
my_string = "I want *this text* to be uppercase"
my_string_modified = func(my_string)
print(my_string)
print(my_string_modified)
Output:
I want *this text* to be uppercase
I want THIS TEXT to be uppercase
There are definitely more "advanced" ways to do this, as pointed out in other answers on this post, but I hope this answer has helped to clarify what's going wrong in your code, how to fix it, and what some good practices are when you write this kind of thing. Writing code this way is, in my opinion, a really good way to understand how algorithmic processes can be designed and implemented.
I think you've tried to make this more complicated than it is. You need to find the index of both asterisks. From that you can get three slices of the original string and apply upper() to the slice between the asterisks. Note that this code will fail if there are fewer than two asterisks in the string.
def dotricks(s):
i = s.index('*')
j = s.index('*', i+i)
return s[0:i] + s[i+1:j].upper() + s[j+1:]
print(dotricks('I want *this text* to be uppercase'))
You are not changing the string in your code. In this edit below, I've assigned the letters of the string to a new variable. And used continue to skip over the "*". Also, at the end your append will give you a list of letters which you need to use .join() to concatentate.
Try this edit to your code, tested and working:
l = []
def func(s):
inside = False
temp = ""
for i in s:
if i == "*" and not inside:
inside = True
continue
if inside:
if i == "*":
inside = False
continue
else:
temp = i.upper()
else:
temp = i
l.append(temp)
new_string = "".join(l)
print(new_string)
return new_string
func("I want *this text* to be uppercase")
There are several issues here:
You don't return anything inside your function
Your while loop is pointless as i is not incremented inside of it
You need to assign i to i.upper()
You need to convey the input to a list
The corrected code would be as follows:
l = []
def func(s):
inside = False
for i in s:
if i == "*" and not inside:
inside = True
while inside:
if i == "*":
inside = False
else:
i.upper()
if i != "*":
l.append(i)
return l
I would leverage the power of the re module:
import re
st = "I want *this text* to be uppercase and *this one*"
v = re.findall("\*(.*?)\*", st)
for s in v:
st = st.replace(f'*{s}*', s.upper())
print(st)
Output:
>>> I want THIS TEXT to be uppercase and THIS ONE
Anyway, re-editing your code:
def func(s):
l = []
inside = False
for i in s:
if i == "*":
inside = not inside # switch inside on/off when * is found
if inside:
i = i.upper() # upper the character if inside == True
l.append(i)
return l
If you look at your original code, part of the problem is in the following logic:
if i == "*" and not inside:
inside = True # inside is set to True when * is found....
while inside:
if i == "*":
inside = False # and immediately set to False again!
I am starting to learn Python and looked at following website: https://www.w3resource.com/python-exercises/string/
I work on #4 which is "Write a Python program to get a string from a given string where all occurrences of its first char have been changed to '$', except the first char itself."
str="restart"
char=str[0]
print(char)
strcpy=str
i=1
for i in range(len(strcpy)):
print(strcpy[i], "\n")
if strcpy[i] is char:
strcpy=strcpy.replace(strcpy[i], '$')
print(strcpy)
I would expect "resta$t" but the actual result is: $esta$t
Thank you for your help!
There are two issues, first, you are not starting iteration where you think you are:
i = 1 # great, i is 1
for i in range(5):
print(i)
0
1
2
3
4
i has been overwritten by the value tracking the loop.
Second, the is does not mean value equivalence. That is reserved for the == operator. Simpler types such as int and str can make it seem like is works in this fashion, but other types do not behave this way:
a, b = 5, 5
a is b
True
a, b = "5", "5"
a is b
True
a==b
True
### This doesn't work
a, b = [], []
a is b
False
a == b
True
As #Kevin pointed out in the comments, 99% of the time, is is not the operator you want.
As far as your code goes, str.replace will replace all instances of the argument supplied with the second arg, unless you give it an optional number of instances to replace. To avoid replacing the first character, grab the first char separately, like val = somestring[0], then replace the rest using a slice, no need for iteration:
somestr = 'restart' # don't use str as a variable name
val = somestr[0] # val is 'r'
# somestr[1:] gives 'estart'
x = somestr[1:].replace(val, '$')
print(val+x)
# resta$t
If you still want to iterate, you can do that over the slice as well:
# collect your letters into a list
letters = []
char = somestr[0]
for letter in somestr[1:]: # No need to track an index here
if letter == char: # don't use is, use == for value comparison
letter = '$' # change letter to a different value if it is equal to char
letters.append(letter)
# Then use join to concatenate back to a string
print(char + ''.join(letters))
# resta$t
There are some need of modification on your code.
Modify your code with as given in below.
strcpy="restart"
i=1
for i in range(len(strcpy)):
strcpy=strcpy.replace(strcpy[0], '$')[:]
print(strcpy)
# $esta$t
Also, the best practice to write code in Python is to use Function. You can modify your code as given below or You can use this function.
def charreplace(s):
return s.replace(s[0],'$')[:]
charreplace("restart")
#'$esta$t'
Hope this helpful.
I have a text file (an output of a different process that I can't alter) which contains logical comparisons (only these three: >, <=, in) stored as strings. Let's say this is a line in my file, which should be evaluated:
myStr = "x>2 and y<=30 and z in ('def', 'abc')"
Some of my variables are categorical and I specify them, and the rest are numerical:
categoricalVars = ('z')
The values of my variables are stored in a dictionary, let's assume these are their values. Note that they always come in as strings, even for numeric variables:
x, y, z = '5', '6', 'abc'
So my question is how I can safely evaluate (i.e. without using eval()) the truth of myStr in reference to this last line.
What I have done is: First change myStr to reflect the data types:
import re
delim = "(\>|\<=|\ in )" # Put in group to find later which delimiter is used
def pyRules(s):
varName = re.split(delim, s)[0]
rest = "".join(re.split(delim, s)[1:])
if varName in categoricalVars:
return varName + rest
else:
return "float(" + varName + ")" + rest
# Call:
[pyRules(e) for e in myStr.split(' and ')]
# Result:
['float(x)>2', 'float(y)<=30', "z in ('def', 'abc')"]
Now I can easily do:
[eval(pyRules(e)) for e in myStr.split(' and ')]
# Result:
[True, True, True]
But I want to avoid this. I tried ast.literal_eval() but got the following error:
import ast
[ast.literal_eval(pyRules(e)) for e in myStr.split(' and ')]
# Result:
Traceback (most recent call last):
File "<ipython-input-556-dae16951de03>", line 1, in <module>
ast.literal_eval(ast.parse(conds[0]))
File "C:\ProgramData\Anaconda2\lib\ast.py", line 80, in literal_eval
return _convert(node_or_string)
File "C:\ProgramData\Anaconda2\lib\ast.py", line 79, in _convert
raise ValueError('malformed string')
ValueError: malformed string
Next, I tried the following approach, which almost gave me the right answer:
def pyRules(s):
varName = re.split(delim, s)[0]
operation = "".join(re.split(delim, s)[1:])
if varName in categoricalVars:
return "'{" + varName + "}'" + operation
else:
return "float({" + varName + "})" + operation
rules = [pyRules(e).format(x='5',y='6',z='abc') for e in myStr.split(' and ')]
# rules is:
['float(5)>2', 'float(6)<=30', "'abc' in ('def', 'abc')"]
I can again use the eval() on this and get [True, True, True] but to avoid it I defined my own inequality checker function:
def check(x):
first, operation, second = re.split(delim, x)
if operation == ">":
return first > second
elif operation == "<=":
return first <= second
elif operation == " in ":
return first in second
# Call:
[check(pyRules(e).format(x='5',y='6',z='abc')) for e in myStr.split(' and ')]
# Result:
[True, False, True]
It is having a hard time evaluating the second item, i.e: 'float(6)<=30' I also recreated this function using the operator module per this SO thread which is essentially the same thing, and got the same result.
I checked pyparsing, couldn't get it to work (which even looks scary, look at this!), and SymPy but unfortunately it also uses eval frequently, as documented in the hyperlink I provided.
Question 2: Is it okay to use eval given that I am 100% sure that I don't have any crazy string that can interfere with os and erase my disk and other crazy stuff like that?
Note: This is a piece of a big code that I built in Python 2, so Python 2 based answers would be ideal; but I can move to Python 3 if anybody thinks my answer is in that sphere.
After a few hours of work, I figured out a way to get ast.literal_eval() to work! My logic is to look at the two sides of, say, x>2, i.e. x and 2, make sure these are safe by evaluating both with literal_eval, and then run it through my check() function, which does the evaluation. Same for z in ('def', 'abc'): First make sure both z and ('def', 'abc') are safe, then do the actual boolean checking with the check() function.
Since I fully trusted my inputs I could've done the easier eval() way, but just wanted to be double-cautious. And wanted to build some code for everybody out there who have security issues (user inputs etc.) and need to safely evaluate logicals. Hope it helps somebody!
Please see my full code below, any comments/recommendations are welcome.
import re
import ast
myStr = "x>2 and y<=30 and z in ('def', 'abc')"
categoricalVars = ('z')
x, y, z = '5', '6', 'abc'
delim = "(\>|\<=|\ in )" # Put in group to find in the func check() which delimiter is used
def pyRules(s):
"""
Place {} around variable names so that we can str.format() in the func check()
"""
varName = re.split(delim, s)[0]
rest = "".join(re.split(delim, s)[1:])
return "'{" + varName + "}'" + rest
def check(x):
"""
If operation is > or <= then it is a numeric var, use double literal_eval to
parse floats e.g. "'5'" (dual quotes) to 5.0. This is equivalent to:
float(ast.literal_eval(first)). Else it is categorical, just literal_eval once
"""
first, operation, second = re.split(delim, x)
if operation == ">":
return ast.literal_eval(ast.literal_eval(first)) > ast.literal_eval(second)
elif operation == "<=":
return ast.literal_eval(ast.literal_eval(first)) <= ast.literal_eval(second)
elif operation == " in ":
return ast.literal_eval(first) in ast.literal_eval(second)
# These are my raw rules:
print [pyRules(e) for e in myStr.split(' and ')]
# These are my processed rules:
print [pyRules(e).format(x='5',y='6',z='abc') for e in myStr.split(' and ')]
# And these are my final results of logical evaluation:
print [check(pyRules(e).format(x='5',y='6',z='abc')) for e in myStr.split(' and ')]
Results of the three result lines:
["'{x}'>2", "'{y}'<=30", "'{z}' in ('def', 'abc')"]
["'5'>2", "'6'<=30", "'abc' in ('def', 'abc')"]
[True, True, True]
Thanks!
My goal is to have the function SRA_Accession return it's values as a string e.g "Value1,Value2,Value3" the code so far is
def SRA_Accession():
SRA=1293518
while (SRA < 1293618):
SRA=SRA+1
print "SRA"+str(SRA)
if False:
break
the lack of tabs are making this not work and you need a return statement which returns everything.
def SRA_Accession():
SRA=1293518
my_list = []
while (SRA < 1293618):
SRA=SRA+1
my_list.append("SRA"+str(SRA))
return ','.join(my_list)
Judging by the way you are writing the statement I would say you were looking to use a yield statement which returns each SRA string all by itself. This means you will need to add commas outside the function like so.
def SRA_Accession():
SRA=1293518
while (SRA < 1293618):
SRA=SRA+1
yield "SRA"+str(SRA)
value = ','.join(list(SRA_Accession()))
print(value)
I've been doing some more CodeEval challenges and came across one on the hard tab.
You are given two strings. Determine if the second string is a substring of the first (Do NOT use any substr type library function). The second string may contain an asterisk() which should be treated as a regular expression i.e. matches zero or more characters. The asterisk can be escaped by a \ char in which case it should be interpreted as a regular '' character. To summarize: the strings can contain alphabets, numbers, * and \ characters.
So you are given two strings in a file that look something like this: Hello,ell your job is to figure out if ell is in hello, what I do:
I haven't quite gotten it perfect, but I did get it to the point where it passes and works with a 65% complete. How it runs through the string, and the key, and checks if the characters match. If the characters match, it appends the character into a list. After this it divides the length of the string by 2 and checks if the length of the list is either greater than, or equal to half of the string. I figured half of the string length would be enough to verify if it indeed matches or not. Example of how it works:
h == e -> no
e == e -> yes -> list
l == e -> no
l == e -> no
...
My question is what can I do better to the point where I can verify the wildcards that are said above?
import sys
def search_string(string, key):
""" Search a string for a specified key.
If the key exists out put "true" if it doesn't output "false"
>>> search_string("test", "est")
true
>>> search_string("testing", "rawr")
false"""
results = []
for c in string:
for ch in key:
if c == ch:
results.append(c)
if len(string) / 2 < len(results) or len(string) / 2 == len(results):
return "true"
else:
return "false"
if __name__ == '__main__':
with open(sys.argv[1]) as data:
for line in data.readlines():
data_list = line.rstrip().split(",")
search_key = data_list[1]
word = data_list[0]
print(search_string(word, search_key))
I've come up with a solution to this problem. You've said "Do NOT use any substr type library function", I'm not sure If some of the functions I used are allowed or not, so tell me if I've broken any rules :D
Hope this helps you :)
def search_string(string, key):
key = key.replace("\\*", "<NormalStar>") # every \* becomes <NormalStar>
key = key.split("*") # splitting up the key makes it easier to work with
#print(key)
point = 0 # for checking order, e.g. test = t*est, test != est*t
found = "true" # default
for k in key:
k = k.replace("<NormalStar>", "*") # every <NormalStar> becomes *
if k in string[point:]: # the next part of the key is after the part before
point = string.index(k) + len(k) # move point after this
else: # k nbt found, return false
found = "false"
break
return found
print(search_string("test", "est")) # true
print(search_string("t....est", "t*est")) # true
print(search_string("n....est", "t*est")) # false
print(search_string("est....t", "t*est")) # false
print(search_string("anything", "*")) # true
print(search_string("test", "t\*est")) # false
print(search_string("t*est", "t\*est")) # true