user20191650
user20191650

Reputation:

How can I reshape a 2D array into 1D in python?

Let me edit my question again. I know how flatten works but I am looking if it possible to remove the inside braces and just simple two outside braces just like in MATLAB and maintain the same shape of (3,4). here it is arrays inside array, and I want to have just one array so I can plot it easily also get the same results is it is in Matlab. For example I have the following matrix (which is arrays inside array):

s=np.arange(12).reshape(3,4)
print(s)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

Is it possible to reshape or flatten() it and get results like this:

[ 0  1  2  3
  4  5  6  7
  8  9 10 11]

Upvotes: 6

Views: 18502

Answers (4)

chrslg
chrslg

Reputation: 13336

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

Upvotes: 0

Andrej Kesely
Andrej Kesely

Reputation: 195418

Try .ravel():

s = np.arange(12).reshape(3, 4)
print(s.ravel())

Prints:

[ 0  1  2  3  4  5  6  7  8  9 10 11]

Upvotes: 5

drx
drx

Reputation: 166

Simply, using reshape function with -1 as shape should do:

print(s)
print(s.reshape(-1))

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[ 0  1  2  3  4  5  6  7  8  9 10 11]

Upvotes: 1

Deepak Tripathi
Deepak Tripathi

Reputation: 3233

you can use itertools.chain

from itertools import chain
import numpy as np
s=np.arange(12).reshape(3,4)
print(list(chain(*s)))
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print(s.reshape(12,)) # this will also work
print(s.reshape(s.shape[0] * s.shape[1],)) # if don't know number of elements before hand

Upvotes: 0

Related Questions