0

I use the following function to create a multidimensional list of shape dimension:

def create(dimensions, elem):
    res = elem
    for i in dimensions[::-1]:
        res = [copyhelp(res) for _ in range(i)]
    return res.copy()

def copyhelp(r): #when res begins as elem, it has no .copy() function
    if isinstance(r,list):
        return r.copy()
    return r

So if I say mylist = create([3,3,2],0), I get

  >> mylist
  [[[0, 0], [0, 0], [0, 0]],
   [[0, 0], [0, 0], [0, 0]],
   [[0, 0], [0, 0], [0, 0]]]

Great. Now I use this function to change the value at an index given by a list index to v:

def replacor(array, index, v):
    if not isinstance(array[0],list):
        array[index[0]] = v
    else:
        return replacor(array[index[0]], index[1:], v) 

Now when I do replacor(mylist, [1,2,0], '.'), I get this:

  >> mylist
  [[['.', 0], [0, 0], [0, 0]],
   [['.', 0], [0, 0], [0, 0]],
   [['.', 0], [0, 0], [0, 0]]]

I'm suspicious it has to do with array pointers, but I used copy() at every step, so I'm not sure where I went wrong. Clearly the issue is the way I define my first list, but I still don't understand why I'm getting this behavior since ints, bools, and strings are immutable.

actinidia
  • 236
  • 3
  • 17
  • 2
    Your `copy` is in the wrong place. `([res]*i).copy()` is pointless, and so is `return res.copy()`. `[res]*i` already *produces a new list*. The problem is that that list simply contains `i` references to the object referenced by `res`. You have to do something like `[res.copy() for _ in range(i)]`. Note this is not an array, but a *list*. – juanpa.arrivillaga Feb 25 '19 at 20:18
  • @juanpa.arrivillaga I tried this, but I'm, getting the same issue. Clearly the issue is the way I define my first list, but I still don't understand why I'm getting this behavior since ints, bools, and strings are immutable. At what point is shallow copying taking place? – actinidia Feb 25 '19 at 21:25
  • Your modified code doesn't run. – juanpa.arrivillaga Feb 25 '19 at 22:27
  • @juanpa.arrivillaga My bad, I "fixed" it but have the same problem. – actinidia Feb 25 '19 at 23:07
  • You're making shallow copies when you need deep copies (but relying on copying for this is a bad idea anyway; a recursive direct construction is simpler and faster, and avoids building a habit of relying on the flaky `copy.deepcopy`). – user2357112 Feb 25 '19 at 23:09
  • @user2357112 Can you explain what you mean by "recursive direct construction"? I thought this *was* a recursive approach. – actinidia Feb 25 '19 at 23:16
  • 1
    Something along the lines of `return elem if not dimensions else [create(dimensions[1:], elem) for _ in range(dimensions[0])]`. – user2357112 Feb 25 '19 at 23:26
  • @user2357112 That's perfect! In general, will recursion avoid these issues when making copies of elements in lists of lists? – actinidia Feb 25 '19 at 23:38
  • It's not really recursion that's the key. It's the fact that instead of trying to create one object and copy it N times, we instead run the creation procedure N times. Recursion just happens to be one of the most natural ways to apply that principle to arbitrarily deeply nested data structures. – user2357112 Feb 26 '19 at 00:00

0 Answers0