sco1
sco1

Reputation: 12214

Writing row from structured numpy array with varying delimiter

I have some data stored in a structured numpy array that I would like to write to a file. Because I'm generating some code to match an existing output format that exported a more visually pleasant table I need to output this data with a varying whitespace delimiter.

Using a basic example:

import numpy as np

x = np.zeros((2,),dtype=('i4,f4,a10'))
x[:] = [(1,2.,'Hello'),(2,3.,'World')]

With a desired output of:

1 2.00    Hello
2 3.00    World

Now, I know I could do this:

for row in x:
    print('%i %.2f    %s' % (row[0], row[1], row[2]))

Which works fine but it seems overly verbose if you have a lot of columns. Right now there are 8 in my output.

I'm new to Python (coming from MATLAB), is there a more generic statement that I could use to 'roll up' all of the columns? I was thinking something along the lines of print('%i %.2f %s' % val for val in row) but this just prints 2 generators. When I ran into a generator while using re.split I could use list() to get my desired output, but I don't think using something similar with, say, str() for this case would do what I'm looking for.

Upvotes: 3

Views: 113

Answers (2)

hpaulj
hpaulj

Reputation: 231385

If you wrap row in a tuple, you don't have to list all the elements. % formats take a tuple. row may display as a tuple but it is actually a numpy.void.

for row in x:
    print('%i %.2f   %s'%tuple(row))

Printing or writing rows in a loop like this is perfectly normal Python.

Class __str__ methods are often written like:

astr=['a header line']
for row in x:
    astr.append('%i %.2f   %s'%tuple(row))
astr='\n'.join(astr)

producing a string of joined lines.

A comprehension equivalent could be:

'\n'.join('%i %.2f   %s'%tuple(row) for row in x)

Since you are using Python3, you could also use the .format approach, but I suspect the % style is closer to what you are using in MATLAB.

Upvotes: 1

Dave J
Dave J

Reputation: 485

First: Regarding your implicit question with the generators; you can "stringify" a generator for example with str.join:

>>> gen = (i.upper() for i in "teststring")
>>> print(''.join(gen))
TESTSTRING

Second: To the actual question: It is a little bit more generic, than your approach, but it is still not really satisfying.

formats = [
    ("{}", 1),      # format and number of spaces for row[0]
    ("{.2f}", 4),   # the same for row[1]
    ("{}", 0)       # and row[2]
]
for row in x:
    lst = [f.format(d) + (" "*s) for (f, s, d) in zip(formats, row)]
    print(*lst, sep='')

It just provides a better overview over each format.

Upvotes: 1

Related Questions