Related
I'm doing string formatting with tuples:
a = (1,2,3)
s = f"something in {a}"
print(s)
'something in (1, 2, 3)'
Everything is fine until I encounter a single-element tuple, which gives:
a = (1,)
s = f"something in {a}"
'something in (1,)'
what I actually want is:
'something in (1)'
How do I make tuple string formatting behaves consistently and remove the trailing comma?
You could use your own formatting logic, e.g.
a = (1,2,3)
s = ','.join([str(x) for x in a])
print(s) # 1,2,3
a = (1,)
s = ','.join([str(x) for x in a])
print(s) # 1
Python have 2 magic methods for formatting values: __str__ and __repr__.
__str__ may return any string, but __repr__ must return string that can be passed to eval and recreate value. It's not required, but you should do it. print tries to use __str__ if it's overriden, otherwise it uses __repr__. This means that you can use eval(repr(some_value)) to clone value, because most builtin types have overridden __repr__ properly. That's why you get trailing comma when formatting (1,).
If you really want to format tuple without trailing comma then use
def format_tuple(value):
return "(" + ",".join(repr(v) for v in value) + ")"
# (1,) -> "(1)"
# () -> "()"
# (1, 2, 3,) -> "(1, 2, 3)"
# (1, 2, 3) -> "(1, 2, 3)"
You can use regex:
import re
tuple = (1,)
s = "something in " + re.sub(r',(?=\))', '', str(tuple))
print(s)
Result:
something in (1)
You don't need any for loop etc.
Based on #Tim Biegeleisen's answer:
a = (1,)
s = f"something in ({','.join([str(x) for x in a])})"
print(s)
'something in (1)'
I am taking l=['1','2','3','rt4','rt5'] as input and I am converting it into l=[1,2,3,'rt4','rt5'] with the following code:
def RepresentsInt(s):
try:
int(s)
return True
except ValueError:
return False
l=['1','2','3','rt4','rt5']
l=[int(l[i]) if RepresentsInt(l[i]) else l[i] for i in range(0,len(l))]
Can I improve above code using a comprehension?
You could change your RepresentsInt function to actually return the integer (if possible) which would make this much easier:
def RepresentsInt(s):
try:
return int(s)
except ValueError:
return s
Then the code to transform the list could be written as (using a for item in l loop is probably better than iterating over the indices):
>>> l = ['1','2','3','rt4','rt5']
>>> [RepresentsInt(item) for item in l]
[1, 2, 3, 'rt4', 'rt5']
Or if you want that as a reusable pattern you still need a helper function (I chose a decorator-like approach here) because you can't use try and/or excepts in comprehensions:
def try_to_apply_func(func, exception):
def newfunc(value):
try:
return func(value)
except exception:
return value
return newfunc
>>> to_int_if_possible = try_to_apply_func(int, ValueError)
>>> [to_int_if_possible(item) for item in l]
[1, 2, 3, 'rt4', 'rt5']
>>> to_float_if_possible = try_to_apply_func(float, ValueError)
>>> [to_float_if_possible(item) for item in l]
[1.0, 2.0, 3.0, 'rt4', 'rt5']
It's really unclear what you want, but maybe something like :
>>> l=['1','2','3','rt4','rt5']
>>> l=[int(i) if i.isdigit() else i for i in l]
>>> l
[1, 2, 3, 'rt4', 'rt5']
You can use the following code to get your desired result.
l = ['1','2','3','rt4','rt5']
l = [int(each) if each.isdigit() else each for each in l]
print l
I don't believe (though I could ultimately be wrong) that there is a cleaner and neater way to achieve this. One solution would be to create an integer parsing lambda expression, such as the following, but I think your current solution is much neater and more robust.
>>> l = ['1','2','3','rt4','rt5']
>>> l = list(map(lambda s : (s.isdigit() or (s[0] == '-' and s[1:].isdigit())) and int(s) or s, l))
>>> l
[1, 2, 3, 'rt4', 'rt5']
This won't correctly catch strings such as '1.0' or ' 1', but it should just about do what you want in two lines.
Following Printing tuple with string formatting in Python, I'd like to print the following tuple:
tup = (0.0039024390243902443, 0.3902439024390244, -0.005853658536585366, -0.5853658536585366)
with only 5 digits of precision. How can I achieve this?
(I've tried print("%.5f" % (tup,)) but I get a TypeError: not all arguments converted during string formatting).
You can print the floats with custom precision "like a tuple":
>>> tup = (0.0039024390243902443, 0.3902439024390244, -0.005853658536585366, -0.5853658536585366)
>>> print('(' + ', '.join(('%.5f' % f) for f in tup) + ')')
(0.00390, 0.39024, -0.00585, -0.58537)
Possible workaround:
tup = (0.0039024390243902443, 0.3902439024390244, -
0.005853658536585366, -0.5853658536585366)
print [float("{0:.5f}".format(v)) for v in tup]
try the following (list comprehension)
['%.5f'% t for t in tup]
Try this:
class showlikethis(float):
def __repr__(self):
return "%0.5f" % self
tup = (0.0039024390243902443, 0.3902439024390244, -0.005853658536585366, -0.5853658536585366)
tup = map(showlikethis, tup)
print tup
You may like to re-quote your question, tuple dnt have precision.
You can iterate over tuple like this, and than you can print result
for python > 3
["{:.5f}".format(i) for i in tup]
And for python 2.7
['%.5f'% t for t in tup]
Most Pythonic way to achieve this is with map() and lambda() function.
>>> map(lambda x: "%.5f" % x, tup)
['0.00390', '0.39024', '-0.00585', '-0.58537']
I figured out another workaround using Numpy:
import numpy as np
np.set_printoptions(precision=5)
print(np.array(tup))
which yields the following output:
[ 0.0039 0.39024 -0.00585 -0.58537]
Here's a convenient function for python >3.6 to handle everything for you:
def tuple_float_to_str(t, precision=4, sep=', '):
return '({})'.format(sep.join(f'{x:.{precision}f}' for x in t))
Usage:
>>> print(funcs.tuple_float_to_str((12.3456789, 8), precision=4))
(12.3457, 8.0000)
you can work on single item.
Try this:
>>> tup = (0.0039024390243902443, 0.3902439024390244, -0.005853658536585366, -0.5853658536585366)
>>> for t in tup:
print ("%.5f" %(t))
0.00390
0.39024
-0.00585
-0.58537
I would like to convert the following string:
s = '1|2|a|b'
to
[1, 2, 'a', 'b']
Is it possible to do the conversion in one line?
Is it possible to do the conversion in one line?
YES, It is possible. But how?
Algorithm for the approach
Split the string into its constituent parts using str.split. The output of this is
>>> s = '1|2|a|b'
>>> s.split('|')
['1', '2', 'a', 'b']
Now we have got half the problem. Next we need to loop through the split string and then check if each of them is a string or an int. For this we use
A list comprehension, which is for the looping part
str.isdigit for finding if the element is an int or a str.
The list comprehension can be easily written as [i for i in s.split('|')]. But how do we add an if clause there? This is covered in One-line list comprehension: if-else variants. Now that we know which all elements are int and which are not, we can easily call the builtin int on it.
Hence the final code will look like
[int(i) if i.isdigit() else i for i in s.split('|')]
Now for a small demo,
>>> s = '1|2|a|b'
>>> [int(i) if i.isdigit() else i for i in s.split('|')]
[1, 2, 'a', 'b']
As we can see, the output is as expected.
Note that this approach is not suitable if there are many types to be converted.
You cannot do it for negative numbers or lots of mixed types in one line but you could use a function that would work for multiple types using ast.literal_eval:
from ast import literal_eval
def f(s, delim):
for ele in s.split(delim):
try:
yield literal_eval(ele)
except ValueError:
yield ele
s = '1|-2|a|b|3.4'
print(list(f(s,"|")))
[1, -2, 'a', 'b', 3.4]
Another way, is using map built-in method:
>>> s='1|2|a|b'
>>> l = map(lambda x: int(x) if x.isdigit() else x, s.split('|'))
>>> l
[1, 2, 'a', 'b']
If Python3, then:
>>> s='1|2|a|b'
>>> l = list(map(lambda x: int(x) if x.isdigit() else x, s.split('|')))
>>> l
[1, 2, 'a', 'b']
Since map in Python3 would give a generator, so you must convert it to list
It is possible to do arbitrarily many or complex conversions "in a single line" if you're allowed a helper function. Python does not natively have a "convert this string to the type that it should represent" function, because what it "should" represent is vague and may change from application to application.
def convert(input):
converters = [int, float, json.loads]
for converter in converters:
try:
return converter(input)
except (TypeError, ValueError):
pass
# here we assume if all converters failed, it's just a string
return input
s = "1|2.3|a|[4,5]"
result = [convert(x) for x in s.split("|")]
If you have all kinds of data types(more than str and int), I believe this does the job.
s = '1|2|a|b|[1, 2, 3]|(1, 2, 3)'
print [eval(x) if not x.isalpha() else x for x in s.split("|")]
# [1, 2, 'a', 'b', [1, 2, 3], (1, 2, 3)]
This fails if there exists elements such as "b1"
map(tuple, map(lambda row: [float(row[0]), int(row[1]), parse(row[2])], res))
Can someone help me with the syntax here? I'm trying to understand specifically what tuple and lambda is referring to.
If it's easier to follow you could rewrite this a few times, from
map(tuple, map(lambda row:
[float(row[0]), int(row[1]), parse(row[2])], res))
to
map(lambda row: (float(row[0]), int(row[1]), parse(row[2])), res)
to
[(float(row[0]), int(row[1]), parse(row[2])) for row in res]
That doesn't really answer your question, but I thought it was easier to read ;)
tuple() is a constructor for a "tuple" object, that can convert a list (or other sequence object) to a tuple.
For example:
>>> a = [1, 2, 3]
>>> a
[1, 2, 3]
>>> tuple(a)
(1, 2, 3)
When used in your example, it converts the result of each lambda expression from a list to a tuple. It seems a bit redundant, because the following should be equivalent:
map(lambda row: (float(row[0], int(row[1], parse(row[2])), res)
Note the use of () parentheses instead of [] square brackets which creates a tuple rather than a list.