1

I am basically trying to re-create numpy's reshape function. The user enters a list and a tuple. The tuple decides the dimension of the matrix.

My idea for finding the rows and columns is:

Take the length of the inputted list at the first or second element of the tuples index. So if the tuples first element is 3 then it should take the len of the arrays first 3 elements.

   def reshape(array: list, rows_columns: tuple):
    
        columns = [len(array(rows_columns[1]))]
    
        rows = [len(array(rows_columns[0]))]
        
        matrix = (rows, columns)
        return matrix
    
   reshape([1, 2, 3, 4], (2, 2))

But this is not possible I get TypeError: 'list' object is not callable. I just wanted to know if I thinking about it wrong.

pam_param
  • 162
  • 1
  • 13
  • When posting a question about code that produces an Exception, always include the complete Traceback - copy and paste it then format it as code (select it and type `ctrl-k`) – wwii Nov 21 '20 at 14:34
  • What were you trying to achieve with `array(rows_columns[1])` – wwii Nov 21 '20 at 14:36
  • `take the len of the arrays first 3 elements.` - hmmm the length of the first three elements should be three - maybe you meant something else? – wwii Nov 21 '20 at 14:39
  • Related: [Understanding slice notation](https://stackoverflow.com/questions/509211/understanding-slice-notation) – wwii Nov 21 '20 at 14:40
  • Related: [How do you split a list into evenly sized chunks?](https://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks). – wwii Nov 21 '20 at 15:31

2 Answers2

2

I think this is how you should be thinking about it. The code does a bit of validation of the arguments up front for consistency. It then loops through the passed array taking slices where each slice (a new list) will be the next row and whose size is the column width and that new list is appended to an initially empty results list (see list.append):

def reshape(array: list, rows_columns: tuple):
    l = len(array)
    assert len(rows_columns) == 2
    n_rows = rows_columns[0]
    n_columns = rows_columns[1]
    assert n_rows * n_columns == l
    results = []
    index = 0
    for _ in range(n_rows):
        results.append(array[index:index+n_columns])
        index += n_columns
    return results

print(reshape([1, 2, 3, 4], (2, 2)))
print(reshape([1, 2, 3, 4], (4, 1)))
print(reshape([1, 2, 3, 4], (1, 4)))
print(reshape([1, 2, 3, 4, 5, 6, 7, 8], (4, 2)))

Prints:

[[1, 2], [3, 4]]
[[1], [2], [3], [4]]
[[1, 2, 3, 4]]
[[1, 2], [3, 4], [5, 6], [7, 8]]
Booboo
  • 38,656
  • 3
  • 37
  • 60
  • This certainly gives the desired output but could you explain the results.append part? – pam_param Nov 21 '20 at 16:04
  • 1
    List append is a standard python operation, often used in a for loop to collect a list of results. – hpaulj Nov 21 '20 at 16:25
  • 1
    I've updated the explanation. `l.append(x)` essentially adds `x` to list `l` as a new element added to the end of the list. In our case `x` is actually a list (i.e. a new row) being added. – Booboo Nov 21 '20 at 16:37
1
import math
import typing as t

def reshape(sequence: t.Sequence, shape: t.Tuple[int, ...]) -> t.Sequence:
    assert len(sequence) == math.prod(shape)
    for n in shape[:-1]:
        sequence = [sequence[i:i + n] for i in range(0, len(sequence), n)]

    return sequence
pypae
  • 639
  • 6
  • 16