I can't copy a list in python [duplicate] - python

This question already has an answer here:
How to clone or copy a list?
17 answers
I'm trying to create a copy of a list and use it inside my function.
import copy
islands=[['a','b','c',],[]]
def transfer(thing):
new_islands=copy.copy(islands)
new_islands[0].remove(thing)
return new_islands
transfer('b')
print(islands)
//output ['a','c']
I have tried other methods of copying such as new_list=old_list[:] and even creating a for loop that appends every element to an empty list, but I still can't get to separate both lists.
Sorry if this has been asked before, but I really couldn't find an answer to my problem.

You need to copy the inner list as well:
islands = [['a','b','c',],[]]
def transfer(thing):
new_islands = [islands[0].copy(), islands[1].copy()]
new_islands[0].remove(thing)
return new_islands
print(transfer('b'), islands) # [['a', 'c'], []] [['a', 'b', 'c'], []]
You can also use deepcopy to copy everything inside the list:
from copy import deepcopy
islands = [['a','b','c',],[]]
def transfer(thing):
new_islands = deepcopy(islands)
new_islands[0].remove(thing)
return new_islands

Let's try to make it simpler and avoid copy at all:
islands=[['a','b','c',],[]]
def transfer(islands, thing):
return islands[0].remove(thing)
transfer(islands, 'b')
print(islands)
//output ['a','c']

Related

Keeping a value when i call a function inside a function?

Given a list, i'm trying to get a random change of two elements. I defined a function dosopt() that does that. Then, I call this function from another function named test(). So in this function "test" i tried to copy the initial argument in the variable x. Then I want to apply de function dosopt() on the variable "v", so it generates the same list "x" but with the interchange of two elements. The thing is that when I do that, the value of x also changes.
I'm not very good at programming so a little bit of help would be nice
from random import randint
import copy as c
def test(other):
x=other[:]
v=dosopt(x)
return x,v
def dosopt(solution):
change=[]
x=0
while x!=1:
i=randint(0,len(solution[0])-2)
j=randint(0,len(solution[0])-2)
if i!=j and i!=j+1 and j!=i+1:
x=1
if i<j:
a=solution[0][i]
b=solution[0][i+1]
c=solution[0][j]
d=solution[0][j+1]
pos=[0,j,b,c]
change.append(pos[:])
solution[0][i+1]=change[0][3]
solution[0][change[0][1]]=change[0][2]
elif i>j:
a=solution[0][j]
b=solution[0][j+1]
c=solution[0][i]
d=solution[0][i+1]
pos=[0,i,b,c]
change.append(pos[:])
solution[0][j+1]=change[0][3]
solution[0][change[0][1]]=change[0][2]
return(solution)
lis=[[0,1,2,3,4,5,6,7,0]]
As I can tell, the problem is on the function dosopt because i don't have this problem with other function.
Please ignore the meaningless lines of code, they come from a previous code.
This is because lists are copied by reference instead of copied by value.
Easiest way to get around this is to use the copy module.
import copy
my_list = ["a", "b", "c"]
same_list = my_list
new_list = copy.deepcopy(my_list)
same_list[0] = "test"
my_list[1] = "something"
new_list[0] = "hello"
print(my_list)
print(same_list)
print(new_list)
results in
['test', 'something', 'c']
['test', 'something', 'c']
['hello', 'b', 'c']
So in your case if you want to copy x and save it you should use v = dosopt(copy.deepcopy(x)). You should be aware though that this could potentially be very slow depending on how big x is.
Also you are shadowing your import of copy as c when you use the variable c later. You should avoid doing this. Plus, copy isn't a long or complicated name so you shouldn't be aliasing it. Aliasing is typically reserved for when things are tedious to type or take up a ton of room on screen such as import matplotlib.pyplot as plt.

Function that would create a copy of lists

I need to a function that would reset the list to its orginal state so in order to do that I would use the copy of a list as its the most straightforward way to achieve it.
Every time I make changes to a list(or number of lists) I would like to have a list in its orginal state. Since the number of lists can be bigger I need a function that can deal with it without repating several lines of code everytime.
I tried to make a function that would simply create a copy of a list and thus I could use it to get a a copy of orginal list for further alterations.
But there is something that I am missing because im getting error:
list1=[1,2,3]
list2=['a','b','c']
list3=[434,52,43]
def copy_lists():
list1c=list1[:]
list2c=list2[:]
list3c=list3[:]
copy_lists()
list1c.append('b')
copy_lists()
#now list1c should be back to orginal
print(list1c)
---------------------------------------------------------------------------
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-95468ead1e78> in <module>()
9
10 copy_lists()
---> 11 list1c.append('b')
12 copy_lists()
NameError: name 'list1c' is not defined
In python you have to be really careful when making copies of objects. If you do list1c = list1 and list1c.append('a') list1 will also have 'a' appended to it. Here is an article talking about when variables are pointers vs an actual copy of the data from another variable.
The best way to make sure that modifying a copy of an object will not change the original is to use the deepcopy function from the copy module.
from copy import deepcopy
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
list3 = [434, 52, 43]
list1c = deepcopy(list1)
list2c = deepcopy(list2)
list3c = deepcopy(list3)
list1c.append('a')
print(list1c)
# list1 will not be modified if you change list1c
print(list1)
The error you are running into now is a scoping problem. When you are trying to use list1c outside the copy_lists() function you are trying to access a local variable outside its scope (in this case the copy_lists function). Here is some reading about scoping in python.
If you would like to do the copying in a function here is a way to do it by returning a tuple from the copy_lists() function.
from copy import deepcopy
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
list3 = [434, 52, 43]
# changed list1 to l1 to avoid having a variable in the inner scope shadow the outer scope
def copy_function(l1, l2, l3):
l1c = deepcopy(l1)
l2c = deepcopy(l2)
l3c = deepcopy(l3)
return l1c, l2c, l3c
list1c, list2c, list3c = copy_function(list1, list2, list3)
list1c.append('a')
print(list1c)
# list1 will not be modified if you change list1c
print(list1)

How do i “save” a list or how can I avoid that a list gets overwritten? [duplicate]

This question already has an answer here:
python list by value not by reference [duplicate]
11 answers
I have this code:
def jaja(lista):
lista.append(2)
return lista
a=[2,3]
b=jaja(a)
print(a,b)
I was hoping to get [2,3] [2,3,2], but for some strange reason list a also changes, so I get [2,3,2] [2,3,2]. Ideas??
a changes because the list gets passed by reference into your function, so when you append in the function, you're appending to the original list. If you don't want the original list to change, make a copy:
def jaja(lista):
lista = lista[:] # a simple way to copy a list in Python
lista.append(2)
return lista
a=[2,3]
b=jaja(a)
print(a,b) # prints [2,3] [2,3,2]

How to use a temporary variable in Python 2.7 - memory

I save 'haystack' in a temporary variable, but when I modify 'haystack', the temporary variable change too. Why? Help please? it's normal? in PHP I didn't have this problem.
# -*- coding:utf-8 -*-
haystack = [1,'Two',3]
tempList = haystack
print 'TempList='
print tempList
iterable = 'hello'
haystack.extend(iterable)
print 'TempList='
print tempList
Return in Console
TempList=
[1, 'Two', 3]
TempList=
[1, 'Two', 3, 'h', 'e', 'l', 'l', 'o']
But I haven't modified the variable 'tempList'.
Help, please.Thanks.
You are not creating a copy of the list; you merely create a second reference to it.
If you wanted to create a temporary (shallow) copy, do so explicitly:
tempList = list(haystack)
or use the full-list slice:
tempList = haystack[:]
You modify the mutable list in-place when calling .extend() on the object, so all references to that list will see the changes.
The alternative is to create a new list by using concatenation instead of extending:
haystack = [1,'Two',3]
tempList = haystack # points to same list
haystack = haystack + list(iterable) # creates a *new* list object
Now the haystack variable has been re-bound to a new list; tempList still refers to the old list.
tempList and haystack are just two names that you bind to the same list.
Make a copy:
tempList = list(haystack) # shallow copy
This is a classic example of the difference of behaviour between lists and standalone variables in Python. This is because tempList = haystack doesn't copy haystack values to tempList, but assigns address of haystack to address of tempList. That is, now you are referring to the same place in memory by two names. So modifying one will modify another. To copy values you can do tempList = list(haystack).

Python's .remove() Method Removes Unexpected Item in List [duplicate]

This question already has an answer here:
How to clone or copy a list?
17 answers
I wrote this script:
soilMod = ['ptaaco']
n = 2
soilModSplit = [soilMod[i:i+n] for i in range(0, len(soilMod), n)] # This returns ['pt', 'aa', 'co']
alphaTest = soilModSplit # I want to maintain the original list built before I remove items below. This returns ['pt', 'aa', 'co'] as well
if 'pt' in soilModSplit:
soilModSplit.remove('pt')
print soilModList # This returns ['aa', 'co']
print alphaTest # This also returns ['aa', 'co'] It's missing the original ['pt', 'aa', 'co'] and I didn't ask the script to remove it from this particular list.
For some reason, when I remove the item ('pt') from soilModSplit, it also removes the item from alphaTest. Is this the expected result? It seems like any variable built on the soilModSplit (in this case, alphaTest) is dependent on any action taken on the soilModSplit. Maybe I am doing something wrong? Is there a way to work around this?
Thanks,
Mike
alphaTest = soilModSplit
alphatest is just a another name for the same list binded to soilModSplit. Make a shallow copy:
alphaTest = list(soilModSplit )
When you do alphaTest = soilModSplit, you are not creating a copy. You just have two names referencing the same list. If you want to save a copy, do alphaTest = list(soilModSplit).

Resources