Use a variable as index in Tkinter - python

How can I use a variable as index in ".get(startindex [,endindex])" expression, instead of numbers ?
I want something like this:
for i in range(1, n):
a = text.get("i.0", "i.end" )
b = text.get("i+1.0", "i+1.end" )
instead of:
a = text.get("1.0", "1.end" )
b = text.get("2.0", "2.end" )
a = text.get("3.0", "3.end" )
b = text.get("4.0", "4.end" ) etc...
In first sequence of code I get "bad text index "i.0" " error.

You have 3 way string format with python
text.get("%d.0"%(i + 1), "%.end"%(i)) # 1
text.get("{0}.0".format(i), "{0}.end".format(i) ) # 2
text.get(f"{i+1}.0", f"{i}.end") # 3

With only this information is hard to say what the purpose of this, but directly answering your question you can use string interpolation python.org such as .format method:
for i in range(1, n):
a = text.get("{0}.0".format(i), "{0}.end".format(i) )
b = text.get("{0}.0".format(i + 1), "{0}.end".format(i + 1))

Related

How to align print output by field when printing key,value pairs in Python [duplicate]

This question already has answers here:
String formatting: Columns in line
(4 answers)
Closed 3 years ago.
I want to print the content of a Python config parser object.
The following code
for section in system_config.config.sections():
print ("\n[" + section + "]")
for (key, value) in system_config.config.items(section):
print(key + "=" + value)
prints
[GENERAL]
data_roots=[["c:\\data", "/data"] , ["d:\\data2", "/data2"]]
test_data_folder=c:\data\atp-test-data
mount_render_python_apps=false
mount_render_modules=false
host_memory=24
host_number_of_cores=4
at_core_threads=15
For readability, the following is preferable:
[GENERAL]
data_roots = [["c:\\data", "/data"] , ["d:\\data2", "/data2"]]
test_data_folder = c:\data\atp-test-data
mount_render_python_apps = false
mount_render_modules = false
host_memory = 24
host_number_of_cores = 4
at_core_threads = 15
In C++ this can be achieved by setting the 'width' of the first field when using the stream operator '<<'.
Question is, how to do this with Python?
You can use {:<30} format to align strings up to 30 of length to left
here is a full example:
import random
import string
def randomstr():
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(random.randint(1,30)))
for _ in range(10):
print('{:<30} = {}'.format(randomstr(), randomstr()))
Sample output
ohpy = bxqoknodteueocokveygkdxmzzxubi
rsulmvnqeyeihchanxrggorlm = vtfeu
cvuhpavispkfbttbadt = d
dgfcqtswqjvywosiikkjdmpyvjhoo = ijx
ainrzifrjrkqfanrxyczs = aluoaoizxtmcrvqv
zpujlyopvrucjqugtaamu = pezh
eot = uizfrxpkjywtlxbgzhrcuuj
hfavmswauekyrtgzrhyxwmbgcyzfq = znwfpuosysirtbkiiimzjkifbueq
qxsqzwkyafcwjrjwnwlradrudush = barehtexzpku
hntgerexophiqbafmwfwdomas = frtsmtakcfztlwfesiijacbmocksqq
You may not know the maximum length of your key strings. But you can do it with something like this in your case maxlen = max(len(k) for k in system_config.config.keys()) and using maxlen in format like this '{:<{width}} = {}'.format(randomstr(), randomstr(), width=maxlen)
.format method of a string, or an f-string.
print( '{:<20}={}'.format(key,value) ) # python 2 friendly
#or
print( f'{key:<20}={value}' )
20 is a guess at the width, I haven't counted it.
Python's built-in str class has an ljust method which performs left text justification given a width and an optional character to fill with.
for section in system_config.config.sections():
print ("\n[" + section + "]")
max_len = max(len(key) for key, _ in system_config.config.items(section))
for key, value in system_config.config.items(section):
print(f'{key.ljust(max_len)} = {value}')

Format a large integer with commas without using .format()

I'm trying to format any number by inserting ',' every 3 numbers from the end by not using format()
123456789 becomes 123,456,789
1000000 becomes 1,000,000
What I have so far only seems to go from the start, I've tried different ideas to get it to reverse but they seem to not work as I hoped.
def format_number(number):
s = [x for x in str(number)]
for a in s[::3]:
if s.index(a) is not 0:
s.insert(s.index(a), ',')
return ''.join(s)
print(format_number(1123456789))
>> 112,345,678,9
But obviously what I want is 1,123,456,789
I tried reversing the range [:-1:3] but I get 112,345,6789
Clarification: I don't want to use format to structure the number, I'd prefer to understand how to do it myself just for self-study's sake.
Here is a solution for you, without using built-in functions:
def format_number(number):
s = list(str(number))[::-1]
o = ''
for a in range(len(s)):
if a and a % 3 == 0:
o += ','
o += s[a]
return o[::-1]
print(format_number(1123456789))
And here is the same solution using built-in functions:
def format_number(number):
return '{:,}'.format(number)
print(format_number(1123456789))
I hope this helps. :D
One way to do it without built-in functions at all...
def format_number(number):
i = 0
r = ""
while True:
r = "0123456789"[number % 10] + r
number //= 10
if number == 0:
return r
i += 1
if i % 3 == 0:
r = "," + r
Here's a version that's almost free of built-in functions or methods (it does still have to use str)
def format_number(number):
i = 0
r = ""
for character in str(number)[::-1]:
if i > 0 and i % 3 == 0:
r = "," + r
r = character + r
i += 1
return r
Another way to do it without format but with other built-ins is to reverse the number, split it into chunks of 3, join them with a comma, and reverse it again.
def format_number(number):
backward = str(number)[::-1]
r = ",".join(backward[i:i+3] for i in range(0, len(backward), 3))
return r[::-1]
Your current approach has following drawbacks
checking for equality/inequality in most cases (especially for int) should be made using ==/!= operators, not is/is not ones,
using list.index returns first occurence from the left end (so s.index('1') will be always 0 in your example), we can iterate over range if indices instead (using range built-in).
we can have something like
def format_number(number):
s = [x for x in str(number)]
for index in range(len(s) - 3, 0, -3):
s.insert(index, ',')
return ''.join(s)
Test
>>> format_number(1123456789)
'1,123,456,789'
>>> format_number(6789)
'6,789'
>>> format_number(135)
'135'
If range, list.insert and str.join are not allowed
We can replace
range with while loop,
list.insert using slicing and concatenation,
str.join with concatenation,
like
def format_number(number):
s = [x for x in str(number)]
index = len(s) - 3
while index > 0:
s = s[:index] + [','] + s[index:]
index -= 3
result = ''
for character in s:
result += character
return result
Using str.format
Finally, following docs
The ',' option signals the use of a comma for a thousands separator. For a locale aware separator, use the 'n' integer presentation type instead.
your function can be simplified to
def format_number(number):
return '{:,}'.format(number)
and it will even work for floats.

Add string in a certain interval position in Python

I have string like this 718868538ddwe. I want to insert back slash ("\") at interval of 3.
I need output like this: 718\868\538\ddw\e.
You can use str.join with a list comprehension:
x = '718868538ddwe'
res = '\\'.join([x[3*i: 3*(i+1)] for i in range(len(x) // 3 + 1)])
print(res)
# 718\868\538\ddw\e
def chunks(input_str):
current = input_str
while current:
next, current = current[:3], current[3:]
yield next
str = ''.join([chunk + '/' for chunk in chunks(input_str)])

Multiple string append together with index

I have multiple string required original string to append different strings. Both of origin string and append string contains 1 int variable Based on my knowledge, both of following code are working but what is the best way to do it or if there is a better way to do it?
or is there any way I can write something like
newstrg = '{}{}'.format(org%OrgInt, appd%appdInt)
first method
org = "org__%s"
appd = "appd__%s"
orgInt = 1
appdInt = 7
newstrg = org % orgInt + appd % appdInt
print(newstrg)
org__1appd__7
Second method
org = "org__{}"
appd = "appd__{}"
orgInt = 1
appdInt = 7
newstrg = (org + appd).format(orgInt, appdInt)
org__1appd__7
Here is another way:
org_appd = {'org': 1, 'appd': 7}
org = "org__{org}"
appd = "appd__{appd}"
newstrg = (org + appd).format(**org_appd)
What about "org__{org}appd{appd}".format (org =1, appd= 7) or similar? Your format string can be arbitrary, and it's cleaner to use named placeholders.
edit
if the tokens and the numbers are variable, feed them in as a list of token-value pairs:
tokenpairs = [('org',1), ('appd', 7)] # etc
unit = lambda t,v : "{0}__{1}".format(t ,v)
renamed = "".join([unit (t, v) for t, v in tokenpairs])

for each gives different result?

I tried to add the comma seprated value between the : seprated then multiply the whole value
For example, consider my value is 1,2,3:4,5,6
I want to add the 1+2+3 ,and 4+5+6 then multiply the result of this value so answer is 6 * 15 = 90
For my bellow data i want the result is 7.224 but this script gives 61.658886435
I don't know what is the problem in my script'
ar = "0.212,1.231,0.112:1.001,3.212,0.002:0.002,0.0001,1.1"
x_data = ar.split(":")
x_final = 1
x_add = 0
for i in x_data:
x_each = i.split(",")
for j in x_each:
x_add = x_add + float(j)
x_final = x_add * x_final
print x_final
Is any possible way to get the result without iterating loop? For above problem
This problem could be also solved in a functional way:
You have to multiply all values in the list - this is what functools.reduce + operator.mul for
You have to sum up all values in all inner lists - this is what sum for
Example:
In [5]: ar = "0.212,1.231,0.112:1.001,3.212,0.002:0.002,0.0001,1.1"
In [6]: import operator
In [7]: import functools
In [8]: functools.reduce(operator.mul, (sum(float(x) for x in s.split(',')) for s in ar.split(':')))
Out[8]: 7.223521582500001
I don't necessarily recommend this complicated expression, but you can do it with list comprehensions and avoid the for loops:
import operator
ar = "0.212,1.231,0.112:1.001,3.212,0.002:0.002,0.0001,1.1"
reduce(operator.mul, [sum([float(n) for n in e]) for e in [x.split(',') for x in ar.split(":")]], 1)
Use missed the initialize value as zero (x_add = 0) in each iterating. So your script add with the previous values
ar = "0.212,1.231,0.112:1.001,3.212,0.002:0.002,0.0001,1.1"
x_data = ar.split(":")
x_final = 1
for i in x_data:
x_each = i.split(",")
x_add = 0 # Here you not initialize it
for j in x_each:
x_add = x_add + float(j)
x_final = x_add * x_final
print x_final
!!! As from #jpmc26 and #soon comment. Avoid using eval, and conform your input string format.
Without looping use regex for to do it
Use regex for solve your problem without looping.
ar = "0.212,1.231,0.112:1.001,3.212,0.002:0.002,0.0001,1.1"
import re
ar = "("+ar #Add the ( with your data
ar = re.sub(r",","+",ar) #Substitute with + instead of ,
ar = re.sub(r"(?=\:|$)",")",ar) #look ahead for add `)` after colon
ar = re.sub(r"(?<=)\:","*(",ar) #Replace the color with *
#NOw you data look likes(0.212+1.231+0.112)*(1.001+3.212+0.002)*(0.002+0.0001+1.1)
#Finally evaluvate the string as a expression
print eval(ar)

Categories

Resources