Saturday, January 5, 2013

Cloning lists including multidimensional lists...

Note this from the Python documentation.


If you just use the assignment function you don't really get a copy but a set of pointers to data that is changed as you change the original anyway.
This excellent summary explains why it is better to use the list() function rather than using [:] for example but this only seems to work for one dimensional arrays?

"...Shallow copies of dictionaries can be made using dict.copy(), and of lists by assigning a slice of the entire list, for example, copied_list =original_list[:]..."


The slice function also needs to be modified for two dimensional arrays as well.  Suggestions including importing numpy or copy to use deepcopy() etc but this seems overkill...

See this post on how to clone 2d lists

Creating an A x B list to use as a matrix in Python



Creating a list that can be used as an A x B matrix in Python is not as straightforward as creating an empty list and then trying to append or insert data to it in the place at the co-ordinates you want. You would end up getting index errors etc.

 Looking at the post on matrix formation here it looks like one method is to start by appending the number of items you need for, say, each column and then taking each column and appending the number of items you need to make up the rows.


 This code shows how:


  1. # create a 2D matrix of zeros and populate it
  2. def make_list(size):
  3. """create a list of size number of zeros"""
  4. mylist = []
  5. for i in range(size):
  6. mylist.append(0)
  7. return mylist
  8. def make_matrix(rows, cols):
  9. """
  10. create a 2D matrix as a list of rows number of lists
  11. where the lists are cols in size
  12. resulting matrix contains zeros
  13. """
  14. matrix = []
  15. for i in range(rows):
  16. matrix.append(make_list(cols))
  17. return matrix
  18. mx = make_matrix(3, 3)
  19. print(mx)
  20. print('-'*34)
  21. # now populate the zero matrix
  22. # for instance put a 5 in row 0, column 0
  23. mx[0][0] = 5
  24. # put a 7 in row 1, column 1
  25. mx[1][1] = 7
  26. # put a 9 in row 2, column 2
  27. mx[2][2] = 9
  28. print(mx)



The * function helps in filling up a list with items, but if you nest it you end up then creating copies of the SAME list again.  This output shows how a nested * ends up working - i.e. you try and change one part of the matrix but instead it is changed in multiple columns (strangely without an index out of range error??)



  1. mx = [[None]*3]*3
  2. print(mx)
  3. mx[1][1] = 7
  4. print(mx)
  5. """
  6. my output -->
  7. looks okay
  8. [[None, None, None], [None, None, None], [None, None, None]]
  9. oops!!!!
  10. [[None, 7, None], [None, 7, None], [None, 7, None]]
  11. """



 However the best way seems to be to use the list function itself as shown here:

list(list(0 for i in range(3)) for j in range(3))

Remember you end up with a list of lists in Python that is referable like a basic array that you are used to.