First answer
If I understood correctly your question (and 4 other answers say I didn't), your problem is not how to flatten()
or reshape(-1)
an array, but how to ensure that even after reshaping, it still display with 4 elements per line.
I don't think you can, strictly speaking. Arrays are just a bunch of elements. They don't contain indication about how we want to see them. That's a printing problem, you are supposed to solve when printing. You can see [here][1] that people who want to do that... start with reshaping array in 2D.
That being said, without creating your own printing function, you can control how numpy display arrays, using np.set_printoptions
.
Still, it is tricky so, because this function allows you only to specify how many characters, not elements, are printed per line. So you need to know how many chars each element will need, to force linebreaks.
In your example:
np.set_printoptions(formatter={"all":lambda x:"{:>6}".format(x)}, linewidth=7+(6+2)*4)
The formatter ensure that each number use 6 chars.
The linewidth, taking into account "array([" part, and the closing "])" (9 chars) plus the 2 ", " between each elements, knowing we want 4 elements, must be 9+6×4+2×3: 9 chars for "array([...])", 6×4 for each 4 numbers, 2×3 for each 3 ", " separator. Or 7+(6+2)×4.
You can use it only for one printing
with np.printoptions(formatter={"all":lambda x:"{:>6}".format(x)}, linewidth=7+(6+2)*4):
print(s.reshape(-1))
Edit after some times : subclass
Another method that came to my mind, would be to subclass ndarray
, to make it behave as you would want
import numpy as np
class MyArr(np.ndarray):
# To create a new array, with args ls: number of element to print per line, and arr, normal array to take data from
def __new__(cls, ls, arr):
n=np.ndarray.__new__(MyArr, (len(arr,)))
n.ls=ls
n[:]=arr[:]
return n
def __init__(self, *args):
pass
# So that this .ls is viral: when ever the array is created from an operation from an array that has this .ls, the .ls is copyied in the new array
def __array_finalize__(self, obj):
if not hasattr(self, 'ls') and type(obj)==MyArr and hasattr(obj, 'ls'):
self.ls=obj.ls
# Function to print an array with .ls elements per line
def __repr__(self):
# For other than 1D array, just use standard representation
if len(self.shape)!=1:
return super().__repr__()
mxsize=max(len(str(s)) for s in self)
s='['
for i in range(len(self)):
if i%self.ls==0 and i>0:
s+='\n '
s+=f'{{:{mxsize}}}'.format(self[i])
if i+1<len(self): s+=', '
s+=']'
return s
Now you can use this MyArr
to build your own 1D array
MyArr(4, range(12))
shows
[ 0.0, 1.0, 2.0, 3.0,
4.0, 5.0, 6.0, 7.0,
8.0, 9.0, 10.0, 11.0]
And you can use it anywhere a 1d ndarray is legal. And most of the time, the .ls
attribute will follows (I say "most of the time", because I cannot guarantee that some functions wont build a new ndarray, and fill them with the data from this one)
a=MyArr(4, range(12))
a*2
#[ 0.0, 2.0, 4.0, 6.0,
# 8.0, 10.0, 12.0, 14.0,
# 16.0, 18.0, 20.0, 22.0]
a*a
#[ 0.0, 1.0, 4.0, 9.0,
# 16.0, 25.0, 36.0, 49.0,
# 64.0, 81.0, 100.0, 121.0]
a[8::-1]
#[8.0, 7.0, 6.0, 5.0,
# 4.0, 3.0, 2.0, 1.0,
# 0.0]
# It even resists reshaping
b=a.reshape((3,4))
b
#MyArr([[ 0., 1., 2., 3.],
# [ 4., 5., 6., 7.],
# [ 8., 9., 10., 11.]])
b.reshape((12,))
#[ 0.0, 1.0, 2.0, 3.0,
# 4.0, 5.0, 6.0, 7.0,
# 8.0, 9.0, 10.0, 11.0]
# Or fancy indexing
a[np.array([1,2,5,5,5])]
#[1.0, 2.0, 5.0, 5.0,
# 5.0]
# Or matrix operations
M=np.eye(12,k=1)+2*M.identity(12) # Just a matrix
M@a
#[ 1.0, 4.0, 7.0, 10.0,
# 13.0, 16.0, 19.0, 22.0,
# 25.0, 28.0, 31.0, 22.0]
np.diag(M*a)
#[ 0.0, 2.0, 4.0, 6.0,
# 8.0, 10.0, 12.0, 14.0,
# 16.0, 18.0, 20.0, 22.0]
# But of course, some time you loose the MyArr class
import pandas as pd
pd.DataFrame(a, columns=['v']).v.values
#array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11.])
[1]: https://stackoverflow.com/questions/25991666/how-to-efficiently-output-n-items-per-line-from-numpy-array