0

I have a 1d array of values in floating point format and I need to print these in 5E16.8 formatting (5 entries per line, real format, 16 spaces per entry) as below

  7.49381113E-01  1.87971394E-14  8.19110455E-01 -2.75795136E-16 -1.12488769E-16
  1.64873995E-01 -7.45597632E-02 -2.34514676E-15 -3.14121102E-17  6.96946913E-02

is there any quick and easy way to specify this output format? Thanks!!

COMPCHEM
  • 55
  • 3

2 Answers2

0

You have two options for string formatting.

  1. str.format(), e.g. '{:16.8E}'.format(4.5)
  2. percent operator, e.g. '%16.8E' % (4.5,)

The former is recommended for Python 3.x and any version higher than 2.6. The percent operator can be used for backwards compatibility with Python 2.5 or lower. For further discussion for which one you should use and where, read here. For some quick examples on how to format strings, check the documentation here.

I'll continue my answer using str.format(), but using the other option would result in a very similar approach.


'{:16.8E}' is what you need, so you want to repeat this 5 times for the whole line and respectively pass it 5 elements to print.

fmt = '{:16.8E}'
line_fmt = fmt * 5
print(line_fmt.format(*arr[0:5])) # `arr` is the name of your 1d array

The syntax *arr[0:5] unpacks the values. This effectively passes 5 different arguments, arr[0], arr[1], arr[2], arr[3], arr[4], instead of one array with 5 elements.

You can use this repeatedly in a loop to print as many lines as you want. However, if you intend to print all elements, it's faster to print them in one go by preparing the string format to have newlines every fifth item.

import numpy as np

items_per_line = 5

np.random.seed(1024)
arr = np.random.random(size=12)

fmt = '{:16.8E}'
line_fmt = items_per_line * fmt

arr_fmt = [line_fmt] * (arr.shape[0] // items_per_line)
remainder = arr.shape[0] % items_per_line
if remainder:
    arr_fmt.append(remainder * fmt)
arr_fmt = '\n'.join(arr_fmt)

print(arr_fmt.format(*arr))

Result

  6.47691231E-01  9.96913580E-01  5.18803264E-01  6.58112731E-01  5.99063472E-01
  7.53067334E-01  1.36247128E-01  4.11711641E-03  1.49508880E-01  6.98439001E-01
  5.93352562E-01  8.99915349E-01
Community
  • 1
  • 1
Reti43
  • 9,656
  • 3
  • 28
  • 44
0

you can play with the formatting of string until you get the desire result, and as you want 5 per line, of the many way you can do that, you can use the gruper recipe from itertools and do something like this:

from itertools import zip_longest

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

def my_print(data,size=5):
    for group in grouper(data,size):
        print( " ".join( "{: .8e}".format(x) for x in group if x is not None) )

in this I take groups of 5 elements at the time and transform every number in the group to the desire format with "{: .8e}".format(x) and then join that together

test

>>> test=[0.749381113, 1.87971394e-14, 0.819110455, -2.75795136e-16, -1.12488769e-16, 0.164873995, -0.0745597632, -2.34514676e-15, -3.14121102e-17, 0.0696946913, 0.0, 0.00002541]
>>> my_print(test)
 7.49381113e-01  1.87971394e-14  8.19110455e-01 -2.75795136e-16 -1.12488769e-16
 1.64873995e-01 -7.45597632e-02 -2.34514676e-15 -3.14121102e-17  6.96946913e-02
 0.00000000e+00  2.54100000e-05
>>> 
Copperfield
  • 8,131
  • 3
  • 23
  • 29