evaluating an expression using values - python

I am trying to evaluate the following expression (exp). I'm trying to replace var[i] in exp by values[i] and evaluate the expression and would really appreciate some help. I have tried re.subs and replace however it isn't working.
exp='((2*3.14)/(550*12))*((R*F*L)/t)'
var=['R','F','L','t']
values=[1202,10.12,15.63,60]
It should output: ((23.14)/(55012))((120210.12*15.63)/60)= 3.016

You can use a f-string with named values and format it with a dict
exp = "((2*3.14)/(550*12))*(({R}*{F}*{L})/{t})"
var = ["R", "F", "L", "t"]
values = [1202, 10.12, 15.63, 60]
valdict = dict(zip(var, values))
print(valdict)
filled = exp.format(**valdict)
print(filled)
print(eval(filled))
Which produces
{'R': 1202, 'F': 10.12, 'L': 15.63, 't': 60}
((2*3.14)/(550*12))*((1202*10.12*15.63)/60)
3.0151464826666667
Of course if you are the one building the var/values, you should skip the two lists and build the valdict directly, which makes it a lot more readable.
And if you want to print only three decimal digits use
print(f"{eval(filled):.3f}")
Which prints 3.015 and not 3.016 as you request, but it should be the right value.
Cheers!

I assume the value for each var is at the same index in the values list
You can just replace a variable with the corresponding value in values list to the exp string
exp='((2*3.14)/(550*12))*((R*F*L)/t)'
var=['R','F','L','t']
values=[1202,10.12,15.63,60]
for i,j in zip(var, values):
exp = exp.replace(i, str(j))
Output:
>>exp
'((2*3.14)/(550*12))*((1202*10.12*15.63)/60)'
You can call eval function to evaluate the value.
>>eval(exp)
3.0151464826666667

If you have only such simple variable names (single letter), then the following will be enough:
expr = '((2*3.14)/(550*12))*((R*F*L)/t)'
var = ['R','F','L','t']
values = [1202,10.12,15.63,60]
for n,v in zip(var, values):
expr = expr.replace(n,str(v))
print(f'{expr} = {eval(expr):.5f}')
Set format specifier to the desired one or remove it.
If you have more complex variables names, try using sympy. Example:
import sympy
var = sympy.symbols('R F L t')
values = [1202,10.12,15.63,60]
expr = sympy.sympify('((2*3.14)/(550*12))*((R*F*L)/t)', evaluate=False)
with sympy.evaluate(False):
num_expr = expr.subs(zip(var, values))
print(f'{num_expr} = {num_expr.doit():.5f}')
Can't get rid of printed '*1/', but you can just remove it by hands:
...
print(f'{num_expr} = {num_expr.doit():.5f}'.replace('*1/','/'))

Related

Fetching values from a list in Python

values = ['random word1', 20, 'random word2', 54]
values = list(map(list,zip(values[::2], values[1::2])))
print(values)
[['random word1', 20], ['random word2', 54]]
Now I want to fetch values
like this:
if ‘random word2’ in values:
get the value associated with random word 2 which is in this case 54.
Note: string words and values are random.
How can I do that?
I need to fetch the correct value.
I think a dictionary over a list is the way to go
d = dict(zip(values[::2], values[1::2]))
print(d['random word1']) # -> 20
try:
value = values[values.index("random words2") + 1]
except ValueError:
value = None
Or, if you need to fecth more values, convert your list to a dictionary and then use the get method. Even for 2 retrievals this will already be more efficient, algorithmically wise:
# make N 2-tuples treating the odd-positioned elements as keys and
# even ones as values, and call the dict constructor with that:
v = dict([i:i+2] for i in range(0, len(values), 2))
v.get("random word2")

How to replace text between parentheses in Python?

I have a dictionary containing the following key-value pairs: d={'Alice':'x','Bob':'y','Chloe':'z'}
I want to replace the lower case variables(values) by the constants(keys) in any given string.
For example, if my string is:
A(x)B(y)C(x,z)
how do I replace the characters in order to get a resultant string of :
A(Alice)B(Bob)C(Alice,Chloe)
Should I use regular expressions?
re.sub() solution with replacement function:
import re
d = {'Alice':'x','Bob':'y','Chloe':'z'}
flipped = dict(zip(d.values(), d.keys()))
s = 'A(x)B(y)C(x,z)'
result = re.sub(r'\([^()]+\)', lambda m: '({})'.format(','.join(flipped.get(k,'')
for k in m.group().strip('()').split(','))), s)
print(result)
The output:
A(Alice)B(Bob)C(Alice,Chloe)
Extended version:
import re
def repl(m):
val = m.group().strip('()')
d = {'Alice':'x','Bob':'y','Chloe':'z'}
flipped = dict(zip(d.values(), d.keys()))
if ',' in val:
return '({})'.format(','.join(flipped.get(k,'') for k in val.split(',')))
else:
return '({})'.format(flipped.get(val,''))
s = 'A(x)B(y)C(x,z)'
result = re.sub(r'\([^()]+\)', repl, s)
print(result)
Bonus approach for particular input case A(x)B(y)C(Alice,z):
...
s = 'A(x)B(y)C(Alice,z)'
result = re.sub(r'\([^()]+\)', lambda m: '({})'.format(','.join(flipped.get(k,'') or k
for k in m.group().strip('()').split(','))), s)
print(result)
I assume you want to replace the values in a string with the respective keys of the dictionary. If my assumption is correct you can try this without using regex.
First the swap the keys and values using dictionary comprehension.
my_dict = {'Alice':'x','Bob':'y','Chloe':'z'}
my_dict = { y:x for x,y in my_dict.iteritems()}
Then using list_comprehension, you replace the values
str_ = 'A(x)B(y)C(x,z)'
output = ''.join([i if i not in my_dict.keys() else my_dict[i] for i in str_])
Hope this is what you need ;)
Code
import re
d={'Alice':'x','Bob':'y','Chloe':'z'}
keys = d.keys()
values = d.values()
s = "A(x)B(y)C(x,z)"
for i in range(0, len(d.keys())):
rx = r"" + re.escape(values[i])
s = re.sub(rx, keys[i], s)
print s
Output
A(Alice)B(Bob)C(Alice,Chloe)
Also you could use the replace method in python like this:
d={'x':'Alice','y':'Bob','z':'Chloe'}
str = "A(x)B(y)C(x,z)"
for key in d:
str = str.replace(key,d[key])
print (str)
But yeah you should swipe your dictionary values like Kishore suggested.
This is the way that I would do it:
import re
def sub_args(text, tosub):
ops = '|'.join(tosub.keys())
for argstr, _ in re.findall(r'(\(([%s]+?,?)+\))' % ops, text):
args = argstr[1:-1].split(',')
args = [tosub[a] for a in args]
subbed = '(%s)' % ','.join(map(str, args))
text = re.sub(re.escape(argstr), subbed, text)
return text
text = 'A(x)B(y)C(x,z)'
tosub = {
'x': 'Alice',
'y': 'Bob',
'z': 'Chloe'
}
print(sub_args(text, tosub))
Basically you just use the regex pattern to find all of the argument groups and substitute in the proper values--the nice thing about this approach is that you don't have to worry about subbing where you don't want to (for example, if you had a string like 'Fn(F,n)'). You can also have multi-character keys, like 'F(arg1,arg2)'.

Find if value exists in multiple list and get names of it

I found similar question, but I'm not able to convert answer to match my needs.
(Find if value exists in multiple lists)
So, basicly, I have multiple lists, and I want to list all of them, which contain current user username.
import getpass
value = getpass.getuser()
rep_WOHTEL = ['user1','user2','user3']
rep_REPDAY = ['user4','user1','user3']
rep_ZARKGL = ['user3','user1','user2']
rep_WOHOPL = ['user3','user2','user5']
#No idea how code below works
w = next(n for n,v in filter(lambda t: isinstance(t[1],list) and t[0].startswith('rep_'), globals().items()) if value in v)
print(w)
If current user is user1, I want it to print rep_WOHTEL, rep_REPDAY and rep_ZARKGL. Code above print only ony of them.
How should I change this part of script, to print all I want?
Like I commented in the linked question, iterating through all of globals() or locals() is a bad idea. Store your lists together in a single dictionary or list, and iterate through that instead.
value = "user1"
named_lists = {
"WOHTEL": ['user1','user2','user3'],
"REPDAY": ['user4','user1','user3'],
"ZARKGL": ['user3','user1','user2'],
"WOHOPL": ['user3','user2','user5']
}
names = [name for name, seq in named_lists.items() if value in seq]
print(names)
Result:
['REPDAY', 'ZARKGL', 'WOHTEL']
Checking if value is in all global lists, and if true, print which list(s) contains the required value.
Code:
rep_WOHTEL = ['user1','user2','user3']
rep_REPDAY = ['user4','user1','user3']
rep_ZARKGL = ['user3','user1','user2']
rep_WOHOPL = ['user3','user2','user5']
value = 'user1'
x = globals().items()
for n,v in filter(lambda t: isinstance(t[1],list) and t[0].startswith('rep_'), x):
if value in v:
print(n)
Output:
rep_REPDAY
rep_ZARKGL
rep_WOHTEL
More info about the used functions:
globals()
dict.items()
filter()
isinstance()
startswith()

my str(float) gets broken on histogram dictionary conversion, how do I stop this?

When attempting to histogram a list of numbers(in str formats) all of my numbers get broken up
for instance
a = ['1','1.5','2.5']
after running my histogram function
my dictionary looks like
{'1': 2, '2': 1, '5': 2, '.': 2}
my histogram function is
def histogram(a):
d = dict()
for c in a:
d[c] = d.get(c,0)+1
return d
I'm doing a project for school and have everything coded in, but when I get to doing the mode portion and I use numbers that aren't specifically int I get the above returns
How can I adjust/change this so it accepts the strings exactly as typed
Python 2.7 on Windows 7x64
You can convert each string element to a float before passing it your histogram function.
a = ['1','1.5','2.5']
a = [float(i) for i in a]
def histogram(a):
d = dict()
for c in a:
d[c] = d.get(c,0)+1
return d
print histogram(a)
There might be an error in your list definition. Running your code I get
{'1': 1, '1.5': 1, '2.5': 1}
If I change the definition of a from
a = ['1','1.5','2.5']
to
a = '1' '1.5' '2.5'
I get the output you showed us.
So please double check how your list is defined.
You can use something like this:
>>> a = ['1','1.5','2.5']
>>> dict.fromkeys(a, 0)
{'1': 0, '1.5': 0, '2.5': 0}
Now you can iterate over keys to set the corresponding value.
I have used the following dict comprehension to reduce my work.
>>> {key: float(key)+1 for key in a}
{'1': 2.0, '1.5': 2.5, '2.5': 3.5}
enjoy :)
The histgram function does work as it's written. If however you you inadvertently .join() your list your histogram with then histogram the resulting object. For instance... t = ['1.0','2.0','2.5'] and
s = s.join(t) s will then be == '1.02.02.5' and histogram(s) will count the decimals as values in the slice. My problem was that I had placed a .join() prior to calling histogram.
My appologies to anyone that wasted any real time on this.

how can I convert a char to variable?

In detail:
I need this formula to work.
string = str(z)+":1.0 "+str(z+1)+":0.0" where z is a variable with a value.
will I be able to input this formula into a dictionary value with a specific key. Like
dicto={'A': 'str(z)+":1.0 "+str(z+1)+":0.0"'}
so that when i see a key value 'A' I should be able to use that formula in the dictionary
As I read your question, you wanted something like this:
dicto = {'A': lambda x: "{0!s}:1.0 {1!s}:0.0".format(x, x + 1)}
dicto['A'](2) # '2:1.0 3:0.0'
Use lambda function:
d = { 'A': lambda z: str(z)+":1.0 "+str(z+1)+":0.0" }
d['A'](5)
# returns: '5:1.0 6:0.0'

Categories