Physicist
Physicist

Reputation: 3048

String formatting in Python with variable number arguments

I have a dict which looks something like

A = {
    'test1':{'q0':[0.123,0.234],'phi0':[0.124,0.4325],'m':[9.42,0.3413]},
    'test2':{'q0':[0.343,0.353],'phi0':[0.2341,0.235]},
    'test3':{'q0':[0.343,0.353],'phi0':[0.2341,0.235],'m':[0.325,0.325],'z0':[0.234,0.314]}
    }

I want to print each individual dictionary:

'test1':                 q0=0.123(0.234) phi0=0.123(0.4325) m=9.42(0.3413)
'test2':                 q0=0.343(0.353) phi0=0.2341(0.235)
'test3': z0=0.234(0.314) q0=0.343(0.353) phi0=0.2341(0.235) m=0.325(0.325)

How to do so in Python 3 using thestring.format()? Since each sub-dictionary has variable number of 'parameters', I am not sure how to accomplish it using some list/dictionary comprehension. Also, if I want to leave some space if that parameter is missing like what is shown, how do I do it? Each dictionary has at most five different parameters (q0,phi0,m,c,z0). I juts print it to the terminal so I don't need something very fancy, but I hope it can be more readible.

Upvotes: 1

Views: 1528

Answers (6)

Narendra
Narendra

Reputation: 1539

Try this:-

A = {
    'test1':{'q0':[0.123,0.234],'phi0':[0.124,0.4325],'m':[9.42,0.3413]},
    'test2':{'q0':[0.343,0.353],'phi0':[0.2341,0.235]},
    'test3':{'q0':[0.343,0.353],'phi0':[0.2341,0.235],'m':[0.325,0.325],'z0':[0.234,0.314]}
    }
for i,j in A.items():
    print i+':',
    for x,y in j.items():
        print "{}= {}({})".format(x,y[0],y[1]),
    print 
#output is same as expected

Upvotes: 0

Martin Evans
Martin Evans

Reputation: 46789

As both your tests and parameters are in dictionaries, you could first sort them to ensure a consistent ordering. Simple sorting may not work though as if you had test13, by default in would appear after test1. You could use the Python library natsort to help with this.

As each set of parameters could have missing values, a quick search could be used to create a list of all of the cols that are needed. You could then reserve space when printing for rows with missing values:

from natsort import natsorted

A = {
    'test1':{'q0':[0.123,0.234],'phi0':[0.124,0.4325],'m':[9.42,0.3413]},
    'test2':{'q0':[0.343,0.353],'phi0':[0.2341,0.235]},
    'test3':{'q0':[0.343,0.353],'phi0':[0.2341,0.235],'m':[0.325,0.325],'z0':[0.234,0.314]},
    'test13':{'q0':[0.343,0.353],'z0':[0.234,0.314]}
    }

sorted_tests = natsorted(A.items())     # Ensure test13 is numerical sorted correctly
# Create a list of all required cols
cols = set()

for test, params in sorted_tests:
    cols.update(params.keys())

cols = sorted(cols)    

for test, params in sorted_tests:
    row = [(col, params.get(col, [])) for col in cols]
    cells = []
    for p, values in row:
        if values:
            cells.append('{:20}'.format('{}={}({})'.format(p, values[0], values[1])))
        else:
            cells.append('{:20}'.format(''))

    print("{:6} : {}".format('{}'.format(test), ''.join(cells)))

This would give you the following output:

test1  : m=9.42(0.3413)      phi0=0.124(0.4325)  q0=0.123(0.234)                         
test2  :                     phi0=0.2341(0.235)  q0=0.343(0.353)                         
test3  : m=0.325(0.325)      phi0=0.2341(0.235)  q0=0.343(0.353)     z0=0.234(0.314)     
test13 :                                         q0=0.343(0.353)     z0=0.234(0.314)

Upvotes: 1

keramat
keramat

Reputation: 4543

use a nested loop:

for m,x in A.items():
    for y,z in x.items():
        print(m,'{0}='.format(y), z[0],'({0})'.format(z[1]))

Upvotes: 1

rnso
rnso

Reputation: 24623

Try following code based on for loop which produces a sorted output:

outlist = []
for a in A:
    outstr = a+":"
    for aa in ('z0', 'q0','phi0','m','c'):
        if aa in A[a]:
            outstr += aa+"="+str(A[a][aa][0])+"("+str(A[a][aa][1])+") "
        else:
            outstr += "                "
    outlist.append(outstr)

for i in sorted(outlist):
    print(i)

Output:

test1:                q0=0.123(0.234) phi0=0.124(0.4325) m=9.42(0.3413)                 
test2:                q0=0.343(0.353) phi0=0.2341(0.235)                                 
test3:z0=0.234(0.314) q0=0.343(0.353) phi0=0.2341(0.235) m=0.325(0.325)          

Upvotes: 0

FatihAkici
FatihAkici

Reputation: 5109

Check if 'z0' is in the keys of the sub-dictionaries, and to those items, apply a slightly different string operation than the ones that don't have that key. Looks a little dirty but produces your output exactly:

for k,v in A.items():
    if 'z0' in v:
        print (k,":","{}={}({})".format('z0',v['z0'][0],v['z0'][1]), " ".join("{}={}({})".format(e,t[0],t[1]) for e,t in v.items() if 'z0' not in e))
    else:
        print (k,":                "," ".join("{}={}({})".format(e,t[0],t[1]) for e,t in v.items()))

Result:

test1 :                 q0=0.123(0.234) phi0=0.124(0.4325) m=9.42(0.3413)
test2 :                 q0=0.343(0.353) phi0=0.2341(0.235)
test3 : z0=0.234(0.314) q0=0.343(0.353) phi0=0.2341(0.235) m=0.325(0.325)

Note: If you really need those single quotes around the tests, i.e. 'test1' instead of test1, you can add "'" to the left and right of k in the two print statements of mine: print ("'",k,"'",...

Upvotes: 1

Kasravnd
Kasravnd

Reputation: 107347

Note that dictionaries are unordered data structures, hence you can't expect any order in printing the items unless you use their ordered equivalent collections.OrderedDict(). Nevertheless, you can use a generator expression within str.join() method :

In [4]: for key, value in A.items():
    print(','.join(("{}: {}={}({})".format(key, t1,t2,t3) for t1, (t2, t3) in value.items())))
   ...:     
test1: q0=0.123(0.234),test1: phi0=0.124(0.4325),test1: m=9.42(0.3413)
test3: q0=0.343(0.353),test3: phi0=0.2341(0.235),test3: m=0.325(0.325),test3: z0=0.234(0.314)
test2: q0=0.343(0.353),test2: phi0=0.2341(0.235)

Also note that since we're doing the following inline unpacking it may raise a ValueError if number of the items in lists is more/less than two.

for t1, (t2, t3) in value.items()

Therefore, make sure that the number of unpacking variables match with the number of items in list.

Upvotes: 5

Related Questions