0

Within my function, I need to change the value of an element in a list to a default (of 10) without changing the original list.

function(orig_list):

dup_list = list(orig_list)

#Setting the appropriate value for the list but don't want to change the original list. 
for i in dup_list:
    if dup_list[dup_list.index(i)][1] == 11 or dup_list[dup_list.index(i)][1] == 12 or dup_list[dup_list.index(i)][1] == 13:
        dup_list[dup_list.index(i)][1] = 10

However, when I call the function in my code later on and print the original list, its also changed. I want the function to do this operation and give me a value but not change the original list.

MT0820
  • 21
  • 1
  • 2
  • 2
    Yes, because `list(orig_list)` makes a shallow copy. You need a deep copy. Note, **never** do `dup_list[dup_list.index(i)]` in a loop. This is unecessarily quadratic time, and actually incorrect if there are duplicates in the list. Instead, iterate over the items **and** indices, `for index, item in enumerate(dupe_list): ...` – juanpa.arrivillaga Feb 27 '20 at 00:11
  • you can use `dup_list = orig_list[:]` – deadshot Feb 27 '20 at 00:15
  • Does this answer your question? [How to clone or copy a list?](https://stackoverflow.com/questions/2612802/how-to-clone-or-copy-a-list) – deadshot Feb 27 '20 at 00:17
  • 1
    @bbrodrigues no, `.copy()` creates a shallow copy. *Any* copy of a list would work the way you are showing. – juanpa.arrivillaga Feb 27 '20 at 00:44
  • Does this answer your question? [List of lists changes reflected across sublists unexpectedly](https://stackoverflow.com/questions/240178/list-of-lists-changes-reflected-across-sublists-unexpectedly) – AMC Feb 27 '20 at 01:36

2 Answers2

1

There are different ways to copy mutable data structures like lists and dictionaries. Shallow copies work if there are only immutable members, but if you have a list inside a list, for example, you need a deep copy.

To illustrate:

from copy import deepcopy

l = [1,['a', 'b', 'c'],3,4]
l2 = list(l)
l3 = l.copy()
l4 = deepcopy(l)


# Mutate original list
l[0] = 10  # All of the copies are unaffected by this.
l[1][0] = 'f' # All of the copies except for the deep copy are affected by mutating a mutable item inside the shallow copy of the list.

print(l, l2, l3, l4)

# Result:
# [10, ['f', 'b', 'c'], 3, 4] [1, ['f', 'b', 'c'], 3, 4] [1, ['f', 'b', 'c'], 3, 4] [1, ['a', 'b', 'c'], 3, 4]
Dewald Abrie
  • 1,392
  • 9
  • 21
  • Unfortunately, I'm not allowed to use imports to finish this code. Is there anyway to do make a deep copy without importing? – MT0820 Feb 27 '20 at 01:13
  • You can do a shallow copy, then recursively dig into the data structure and do replacement with shallow copies of any structure that has the copy method defined. – Dewald Abrie Feb 27 '20 at 23:10
0

If you're not are not allowed to import anything to deep copy the list then you can do it yourself with a simple recursive function. My example below assumes that your list consists only of of immutables items (float, int, str, tuple, etc) and lists of the same. For example it wouldn't deep copy a dictionary (but you could add that):

old = [[1, 2,3], [3, 4,[2, 3, 4], 2, [1,2]]]


def deep_copy_list(inlist):
   results = []
   for item in inlist:
       if type(item) != list:     # item is not a list so just append to results
           results.append(item)
       else:
           results.append(deep_copy_list(item))  # item is a list so append a copy
   return results

new = deep_copy_list(old)

print("id of element 0 of old is", id(old[0]))
print("id of element 0 of new is", id(new[0]))

id of element 0 of old is 136833800
id of element 0 of new is 151480776

(The print statements just show that (for example) the list that is in element 0 of the old list has been copied into a new list with a new id value.)

Then once you have the new list that is a deep copy of the original list, you can modify the original list as in previous solutions

quizdog
  • 473
  • 3
  • 8
  • Why not let your variable names breathe a bit? Isn't `deep_copy_list` much clearer than `deepcopylist` ? – AMC Feb 27 '20 at 01:37
  • sure deep_copy_list is good too, it started out as deepcopy which seemed find but then I decided to add a 'list' qualifier and it got a little long. I'll throw in the _s – quizdog Feb 27 '20 at 01:40