Python Parameterize Formatting - python-3.x

So I was wondering if there was a way to parameterize the format operator
For example
>>> '{:.4f}'.format(round(1.23456789, 4))
'1.2346
However, is there anyway to do something like this instead
>>> x = 4
>>> '{:.xf}'.format(round(1.23456789, x))
'1.2346

Yes, this is possible with a little bit of string concatenation. Check out the code below:
>>> x = 4
>>> string = '{:.' + str(x) + 'f}' # concatenate the string value of x
>>> string # you can see that string is the same as '{:.4f}'
'{:.4f}'
>>> string.format(round(1.23456789, x)) # the final result
'1.2346'
>>>
or if you wish to do this without the extra string variable:
>>> ('{:.' + str(x) + 'f}').format(round(1.23456789, x)) # wrap the concatenated string in parenthesis
'1.2346'

Related

Sympy -- Simplify and gather different variables for variable transformation

In a sympy expression I would like to gather all sub expressions of (x*y)
and replace it by z, wherever possible. In a very simple example, that means performing the map
x*a*y+ (x*y**2) -> a*(x*y) + (x*y)*y -> a*z + z*y
The full code is with another example is
from sympy import symbols,Function,Derivative
from sympy import simplify, exp, cos, sin,log
x,y,z = symbols('x y z')
a,b,c = symbols('a b c')
f,g = Function('f')(x),Function('g')(x)
# Simplify the expression such that all combinations of (x*y) can be replaced by c
expr_1 = ((x**2+y)*y*exp(-c+2*log(x*c*y)))/(x**3*c*y**2)
#simplify(expr_1) ?
In a final step, I would like to replace two functions f*g by h
expr_2 = f*g + f*Derivative(g,x) + Derivative(f*g, x) -> h + f*Derivative(g,x) + Derivative(h, x)
Sometimes an algebraic substitution will do what you want:
>>> eq
a*x*y + x*y**2
>>> eq.subs(x,z/y)
a*z + y*z
But you could just as well have done subs(y,z/x) but that would not have led to as simple of an expression. In such cases you can try both and take the simpler of the two:
>>> from sympy import ordered
>>> next(ordered([eq.subs(x,z/y),eq.subs(y,z/x)]))
a*z + y*z
For expr_1
>>> eq=((x**2+y)*y*exp(-c+2*log(x*c*y)))/(x**3*c*y**2)
>>> next(ordered([eq.subs(x,z/y),eq.subs(y,z/x)]))
c*z*(x**2 + z/x)*exp(-c)/x**2
>>> next(ordered([eq.subs(x,c/y),eq.subs(y,c/x)]))
y**2*(c**2/y**2 + y)*exp(-c)
>>> simplify(_)
(c**2 + y**3)*exp(-c)
The ordered strategy should also work for expr_2.

Performance Issue: Lookup sub-value of python dictionary if it is matching another value

I have a python dictionary as follows. Same way, dictionary might have 2 comma separate values for 'Var'(i.e. Dep1,Dep2) and then their respective SubValue (ABC1||A1B1||B1C1, ABC2||A2B2||B2C2).
I'm trying to extract value A1B1 (or A1B1 and B1C1 if there are two Var) with a match of mainValue 'ABC1' and prefix of SubVal 'ABC1'.
ld = { 'id' : 0
'Var': 'Dep1'
'SubVal': 'ABC1||A1B1,ABC2||A2B2,ABC3||A3B3',
'MainValue': 'ABC1'}
So far I tried splitting Subval into list (splitting by comma) and then convert each pair (|| separated) into another dictionary and then looking up the match.
Can anyone suggest a better approach in terms of performance to do this?
Let:
>>> ld = { 'id' : 0, 'Var': 'Dep1', 'SubVal': 'ABC1||A1B1,ABC2||A2B2,ABC3||A3B3', 'MainValue': 'ABC1'}
Your split + dict solution is roughly (note the maxsplit parameter to handle ABC1||A1B1||B1C1 cases):
>>> def parse(d):
... sub_val = dict(t.split('||', maxsplit=1) for t in ld['SubVal'].split(","))
... return sub_val[d['MainValue']]
>>> parse(ld)
'A1B1'
A benchmarck gives:
>>> import timeit
>>> timeit.timeit(lambda: parse(ld))
1.002971081999931
You build a dict for a one shot lookup: that's a bit overkill. You can perform a direct lookup for the MainValue:
>>> def parse_iter(d):
... mv = d['MainValue']
... g = (t.split('||', maxsplit=1) for t in d['SubVal'].split(","))
... return next(v for k, v in g if k == mv)
>>> parse_iter(ld)
'A1B1'
It is a little faster:
>>> timeit.timeit(lambda: parse_iter(ld))
0.8656512869993094
A faster approach is to look for the MainValue in the the ld[SubVal] string and extract the right SubVal. (I assume the MainValue can't be a SubVal or a substring of a SubVal).
With a regex:
>>> import re
>>> def parse_re(d):
... pattern = d['MainValue']+"\|\|([^,]+)"
... return re.search(pattern, d['SubVal']).group(1)
>>> parse_re(ld)
'A1B1'
This is around 25 % faster than the first version on the example:
>>> timeit.timeit(lambda: parse_re(ld))
0.7367669239997667
But why not perform the search manually?
>>> def parse_search(d):
... s = d['SubVal']
... mv = d['MainValue']
... i = s.index(mv) + len(mv) + 2 # after the ||
... j = s.index(",", i)
... return s[i:j]
>>> parse_search(ld)
'A1B1'
This version is around 60% faster than the first version (on the given example):
>>> timeit.timeit(lambda: parse_search(ld))
0.3840863969999191
(If the MainValue can be a SubVal, you can check if there is a comma before the MainValue or SubVal starts with MainValue.)

write multiple values on single input

Following code converts numbers into letters, but I can only input one number at a time.
import string
def translate():
d = dict(enumerate(string.ascii_lowercase, 0))
message = d[int(input('Enter:'))]
print(message)
translate()
example of what I'm trying to do:
Enter: 25345265
then it would output all numbers into their corresponding letters
This could be your basic approach:
>>> import string
>>> d = {str(k):v for k,v in enumerate(string.ascii_lowercase)}
>>> message = input('Enter:')
Enter:2 5 3
>>> print("".join(d[x] for x in message.split()))
cfd
>>> message = input('Enter:')
Enter:25 3
>>> print("".join(d[x] for x in message.split()))
zd
>>> message = input('Enter:')
Enter:8 26 5 3
To deal with values outside of your range you can always either just not accept those number or deal with them with a default value like '*'
>>> message = input('Enter:')
Enter:8 26 5 25
>>> print("".join(d.get(x,'*') for x in message.split()))
i*fz

Writing a function in Python 3 to convert base 16 to base 10

Is there an easy way to modify this code which converts from base 2 into base 10 to work for converting base 16 into base 10? My objective is to build a dedicated function for conversion and not use any built-in Python features for the calculation. Thanks
BinaryVal = int(input('Enter:')
DecVal = 0
for n in range(len(str(BinaryVal))):
Power = len(str(BinX))-(n+1)
DecVal += int(str(BinaryVal)[n])*(2**Power)
print(DecVal)
Yikes.
int already can convert from any base to base 10 - just supply it as the second argument.
int('101010',2)
Out[64]: 42
int('2A',16)
Out[66]: 42
To convert hexadecimal string to int:
>>> hexstr = '101010'
>>> int(hexstr, 16)
1052688
The same -- without int constructor:
>>> import binascii
>>> int.from_bytes(binascii.unhexlify(hexstr), 'big')
1052688
The same -- similar to #SzieberthAdam's answer:
>>> hex2dec = {d: i for i, d in enumerate('0123456789abcdef')}
>>> sum(hex2dec[h] * 16**pos for pos, h in enumerate(reversed(hexstr.lower())))
1052688
or:
>>> from functools import reduce
>>> reduce(lambda n, h: n*16 + hex2dec[h], hexstr.lower(), 0)
1052688
that is equivalent to:
def hex2int(hexstr):
n = 0
for h in hexstr.lower():
n = n*16 + hex2dec[h]
return n
Example:
>>> hex2int('101010')
1052688
As an alternative, one could convert all digits to int first:
>>> reduce(lambda n, d: n*16 + d, map(hex2dec.get, hexstr.lower()))
1052688
It raises TypeError for empty strings.
Well, here you go then:
>>> binary_num = '101010'
>>> sum(int(b)*2**i for i, b in enumerate(reversed(binary_num)))
42

Python write a list to a text file

I am using python format method to write a list of numbers into a text file. When the list length is fixed I can do:
a = [16,1,16,1]
myfile.write('{0},{1},{2},{3}'.format(*a) + "\n")
My question is how to use the format method when the size of list is not fixed. Is there any easy easy way of doing this? Rather than first create a string b, and then map a to b. I am not sure if I can use something like myfile.write('{all elements in a}'.format(*a) + "\n")
b=''
for i in range(len(a)):
if i<(len(a)-1):
b=b+'{'+ str(i) + '},'
else:
b=b+'{'+ str(i) + '}'
myfile.write(b.format(*a) + "\n")
Use str.join:
>>> lis = [16,1,16,1]
>>> ','.join(str(x) for x in lis) + '\n'
'16,1,16,1\n'
>>> lis = range(10)
>>> ','.join(str(x) for x in lis) + '\n'
'0,1,2,3,4,5,6,7,8,9\n'

Resources