This question already has answers here:
How to deep copy a list?
(10 answers)
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
What is the best way to copy a list? [duplicate]
(7 answers)
Closed 1 year ago.
Let's assume that a is some reference variable and I want to put it into a list three times:
a = [1,2,3]
b = [a]*3
>>> b
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
So this still works as expected. But if I append an element to one of the reference variables it is reflected to all of them:
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
Does this happen because the * operator in the first code block only copies the references and the list only points to a? Do I need a for-loop in order to be able to have a list of independent reference variables (copies) n times? (where n is 3 in the example above)
How excactly does the * operator work in this instance?
With a for-loop and the append()-Method the behaviour is the same - are references also used here?:
>>> a = [1,2,3]
>>> b = []
>>> for i in range(2):
... b.append(a)
...
>>> b
[[1, 2, 3], [1, 2, 3]]
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4], [1, 2, 3, 4]]
When inserting copies the behaviour is as expected:
>>> a = [1,2,3]
>>> b = []
>>> for i in range(2):
... b.append(a.copy())
...
>>> b
[[1, 2, 3], [1, 2, 3]]
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4], [1, 2, 3]]
Is there a shorter, more convenient way to do this than to loop with .append() and .copy() as I did above?
My Python-Version is Python 3.8.6
Note that my questions go beyond just using deep_copy() as it is about inserting elements more often in a list and the *-operator - I know what deep_copy() is!
Related
This question already has answers here:
python: changes to my copy variable affect the original variable [duplicate]
(4 answers)
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 4 years ago.
As I don't know what title should be given to my this confusion so I'm putting it just a doubt
a = [1,2,3,4,5]
b = a
for i in range(len(a)):
c = (i - 4)
print(a)
print(b)
b[c] = a[i]
print(a)
print(b)
output
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]
[1, 1, 3, 4, 5]
[1, 1, 3, 4, 5]
[1, 1, 3, 4, 5]
[1, 1, 3, 4, 5]
[1, 1, 1, 4, 5]
[1, 1, 1, 4, 5]
...
why values of list a is getting in each step of loop?
Your problem lies in this line:
b = a
This doesn't do what you think it does. In particular, it does not make a copy of a. After the assignment, both b and a refer to the same object. Thus, any change to b is reflected in a also.
One way to force a shall copy is to use the slice syntax:
b = a[:]
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 6 years ago.
It is quite a silly question, but I am really confused.
Please have a look my code:
>>> my_list = [1, 2, 3]
>>> my_list_new = my_list[:]
>>> my_list_new[0] = 100
>>> my_list_new
[100, 2, 3]
>>> my_list
[1, 2, 3]
So it works as it should. I copied my_list. When I changed the my_list_new - only one list changed.
Now look here:
>>> my_list2 = [[1, 2, 3], [4, 5, 6]]
>>> my_list_new2 = my_list2[:]
>>> my_list_new2[0][0] = 100
>>> my_list_new2
[[100, 2, 3], [4, 5, 6]]
>>> my_list2
[[100, 2, 3], [4, 5, 6]]
As you can see I changed my_list_new2, but both lists changed. Is it normal Python behaviour for nested lists? How to avoid it?
This should work as intended
my_list_new2 = [list[:] for list in my_list2]
Proof
my_list2 = [[1, 2, 3], [4, 5, 6]]
my_list_new2 = [list[:] for list in my_list2]
my_list_new2[0][0] = 100
my_list_new2
[[100, 2, 3], [4, 5, 6]]
my_list2
[[1, 2, 3], [4, 5, 6]]
List are mutable in python. Meaning:
a = [1,2,3]
b = a
a[0] = 4
print(b)
Will print [4, 2, 3]
So in case of nested lists you only copy the "outer" list, and modify the inner list, so you will modify the other list as well. If you are interested in this look up list pointers in python
Solution:
my_list2 = [[1, 2, 3], [4, 5, 6]]
my_list_new2 = [inner_lst.copy() for inner_lst in my_list2] # You can use inner_lst[:] as well
my_list_new2[0][0] = 100
print(my_list2)
Returns: [[1, 2, 3], [4, 5, 6]]
A list of lists (in your case l1 = [[1, 2, 3], [4, 5, 6]]) contains objects (list).
A slice of a list is a new shallow copy of that subset of the list where it inserts references to the objects. It can be seen from the following snippet code.
l1 = [[1, 2, 3], [4, 5, 6]]
l2 = l1[:]
print(id(l1)) # 4406414512
print(id(l2)) # 4382080248
# Shallow copy, insert references
print(id(l1[0])) # 4439177768
print(id(l2[0])) # 4439177768
To copy everything, use copy.deepcopy where it inserts copies of the objects. It can be seen from,
import copy
l1 = [[1, 2, 3], [4, 5, 6]]
l2 = copy.deepcopy(l1)
l2[0][0] = 100
print(l1) # [[1, 2, 3], [4, 5, 6]]
print(l2) # [[100, 2, 3], [4, 5, 6]]
Your outer list my_list2 contains references to two other lists.
Even if you make an independent copy the outer list my_list2, it will still (initially) contain the same items, i.e. the same references to the same two lists. (If you're familiar with C/C++, you can loosely think of the references-to-lists as pointers.) That's called a "shallow copy". Here are a few ways of creating a shallow copy:
my_new_list2 = list(my_list2)
my_new_list2 = [item for item in my_list2]
my_new_list2 = my_list2[:]
import copy; my_new_list2 = copy.copy(my_list2)
To get the behaviour you want, you will need to duplicate the inner lists too. You can do that by hand, as others have suggested—or you can let the Python standard library do it automatically. That's what copy.deepcopy is for:
import copy
my_list_new2 = copy.deepcopy(my_list2)
The advantage of deepcopy is that it will work its way down an arbitrary number of levels of nesting, not necessarily just the first inner level.
Trenutno_stanje is list
povijest is list of lists
epsilon_okolina is function that gives list for a string (pocetno):
trenutno_stanje.append(pocetno)
trenutno_stanje.extend(epsilon_okolina[pocetno])
povijest.append(trenutno_stanje)
povijest should be essentialy list of lists, but it somehow in code duplicates entities
in a way it can be avoided.
What I would like to know is how to remove duplicate of strings in lists of a list?
I tried:
for p in povijest:
p=list(set(p))
But it changed nothing
In your for loop you are just reassigning p and not actually changing the povijest list. Also, set only works on hashable types, and list certainly is not one. You want to use list comprehension after you cast the lists inside the main list into something that can be hashed (like a tuple, which is an immutable list) and then turn that into a set.
>>> a = [1, 2, 3, 4]
>>> b = [1, 2, 3, 4]
>>> c = [1, 3, 4]
>>> i1 = [a, b, c]
>>> set([tuple(x) for x in i1])
set([(1, 2, 3, 4), (1, 3, 4)])
>>> b = [[1,2,3, 3], [3, 2, 4,4]]
>>> b = [ list(set(x)) for x in b ]
>>> b
[[1, 2, 3], [2, 3, 4]]
If you curious about the order try this ,
>>> a=[1,2,3,4,5]
>>> b=[2,3,1,2]
>>> c=[1,2,3,4,5]
>>> z=[a,b,c]
>>> dict((x[0], x) for x in z).values()
[[1, 2, 3, 4, 5], [2, 3, 1, 2]]
This question already has answers here:
What do ellipsis [...] mean in a list?
(5 answers)
Circular Reference with python lists
(3 answers)
Closed 9 years ago.
I've created a list in python,
list1 = [1,2,3,4]
and tried to append it tp itself,
list1.append(list1)
this is what i've got, it's kind of never ending!
could someone please explain me what is happening?
>>> list1=[1,2,3,4]
>>> list1.append(list1)
>>> list1
[1, 2, 3, 4, [...]]
>>> len(list1)
5
>>> len(list1[4])
5
>>> print list1[4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4][4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4][4][4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4][4][4][4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4][4][4][4][4][4]
[1, 2, 3, 4, [...]]
>>> print list1[4][4][4][4][4][4][4][4][4]
[1, 2, 3, 4, [...]]
that's never ending.
Thank You
Names in Python are pointers to objects. In this case
>>> lst = [1, 2, 3, 4]
you create a new list object with 4 int values in, and assign that to the name lst. Next
>>> lst.append(lst)
you add a new item to the end of your list; a pointer to the list itself. This creates the circular reference, that Python prints as [...]. This is because the last item in lst points to lst, in which the last item points to lst, in which...
If you want to append the content of the list to your list, you need to copy the object, which you can do with a slice:
>>> lst.append(lst[:])
>>> lst
[1, 2, 3, 4, [1, 2, 3, 4]]
This question already has answers here:
Confusing [...] List in Python: What is it?
(9 answers)
Closed 9 years ago.
I just seen a output like below - just want to know what is happening here.
>>> l = [1,2,3,4]
>>> l[0]=l
>>> l
[[...], 2, 3, 4]
Why the l[0] value has displayed like this? Can anyone explain me why this behavior.
I was thinking it'd return like, [[1,2,3,4], 2, 3, 4].
Cheers,
Kalai
It shows the ... because otherwise it would have to infinitely recurse.
A list object in Python is a pointer to a list- assigning it like l[0] = l doesn't make a copy. For instance, try
l1 = [1, 2, 3, 4]
l2 = [1, 2]
l2[0] = l1
print l2
# [[1, 2, 3, 4], 2]
l2[0].append(5)
print l1
# [1, 2, 3, 4, 5]
Notice that even though you never changed l1 explicitly, it has now been appended to.
Therefore, when you place a list within itself, that item of the list is still a link to the entire list. After your code above, try doing:
l[1] # ==> 2
l[0][1] # ==> 2
l[0][0][1] # ==> 2
Use a copy of the list to avoid infinite recursion:
In [10]: l = [1,2,3,4]
In [11]: l[0] = l[:]
In [12]: l
Out[12]: [[1, 2, 3, 4], 2, 3, 4]
If you would have used a PrettyPrinter, the output would had been self explanatory
>>> l = [1,2,3,4]
>>> l[0]=l
>>> l
[[...], 2, 3, 4]
>>> pp = pprint.PrettyPrinter(indent = 4)
>>> pp.pprint(l)
[<Recursion on list with id=70327632>, 2, 3, 4]
>>> id(l)
70327632