Python list change index value of one after duplication [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 7 years ago.
As a hypothetical example:
>>> a = [1, 2, 3]
>>> b = a
>>> b[0] = 4
>>> b
[4, 2, 3]
>>> a
[4, 2, 3]
I know that this occurs because the references to both a and b are identical, and therefore point to the same bytes of memory. A change in the bytes referenced by b will be reflected in a, since they share the same memory.
What is the best way to work around this, so that a remains the original value, and after b is made from a, changes to b will not go to a, also.
Specific code:
outputs = []
a = [[0,2,5],[4,2,0],[6,0,0]]
for i in range(3):
for j in range(3):
if not a[i][j]:
b = a
b[i][j] = 1
outputs.append(b)
This returns:
outputs = [[[1,2,5],[4,2,1],[6,1,1]],
[[1,2,5],[4,2,1],[6,1,1]],
[[1,2,5],[4,2,1],[6,1,1]]]

You can copy the original list by slicing it:
a = [1, 2, 3]
b = a[:]
Or using the built in list list() funtion:
b = list(a)
You could also use list comprehension in place of your nested for loops:
b = [[i if i else 1 for i in j] for j in a]

This :
new_list = list(old_list)
And so this will happen -
>>> a = [1,2,3]
>>> b = list(a)
>>> b.append(8)
>>> b
[1, 2, 3, 8]
>>> a
[1, 2, 3]

Related

Assigning values to list of lists changes member list [duplicate]

This question already has answers here:
Unexpected change of list value [duplicate]
(3 answers)
Immutable vs Mutable types
(18 answers)
Closed 2 years ago.
I would like to know why a is not changed in the code below, but f is changed.
After assigning 5 to c[0], a remains 2 and c[0] changes from 2 to 5. This makes sense to me because I did not assign a value to a.
After assigning 8 to t[0][0], f[0] is changed from 1 to 8. This does not make sense to me, because I am changing t not f.
a = 2
b = 3
c = [a,b]
print(c)
print(a)
c[0]= 5
print(c)
print(a)
f = [1,1,1]
s = [2,2,2]
t = [f,s]
print(t)
print(f)
t[0][0] = 8
print(t)
print(f)
output:
[2, 3]
2
[5, 3]
2
[[1, 1, 1], [2, 2, 2]]
[1, 1, 1]
[[8, 1, 1], [2, 2, 2]]
[8, 1, 1]
What is happening here is that lists are treated by reference in python, what this means is that when you write this:
f = [1,1,1]
s = [2,2,2]
t = [f,s]
t[0] is pointing to the list f and f[0] is pointing to the value 1 in other words when you change t[0][0] = 8 in someway you are saying f[0] = 8.
Below is how it should look the memory before and after the assignation of t[0][0] = 8
image of how should lool the memory1
Python has a default aliasing property with assigning objects. we can verify this using "is" operator.
is "a" and "b" are two different list "is" operation will return a False.
a = [1,2,3]
b = [1,2,3]
print(a)
[1, 2, 3]
print(b)
[1, 2, 3]
print(a==b)
True
print(a is b)
False
if "a" is assigned to "c" , on doing "is" operation will receive a True. means both objects are same, or poiting to same memory.
assign a to c
c = a
print(a == c)
True
print(a is c)
True
a and c are pointing to same object, changes on one list will get updated on other object also
a[0]=5
print(a)
[5, 2, 3]
print(c)
[5, 2, 3]
we can do a explicit copy or cloning of existing list.
cloning using slicing
d=a[:]
print(a==d)
True
print(a is d)
False
d[0] = 6
print(d)
[6, 2, 3]
print(a)
[5, 2, 3]
Please try below code.
f = [1,1,1]
s = [2,2,2]
t = [f[:],s[:]]
print(t)
[[1, 1, 1], [2, 2, 2]]
t[0][0] = 8
print(t)
[[8, 1, 1], [2, 2, 2]]
print(f)
[1, 1, 1]

Is there a way to perform calculations with two lists together in Python? [duplicate]

This question already has answers here:
How do I iterate through two lists in parallel?
(8 answers)
How to perform element-wise multiplication of two lists? [duplicate]
(15 answers)
Closed 2 years ago.
For example, if I want values in list a to multiply with values of the same position in list B :
A = [1,2,3]
B = [4,5,6]
Then the desired calculations are:
1 multiplied by 4, 2 multiplied by 5 and 3 multiplied by6
Iterate through two lists at a time using the zip function.
A = [1, 2, 3]
B = [4, 5, 6]
C = []
for a, b in zip(A, B):
C.append(a*b)
print(C)
# Prints [4, 10, 18]
Using list comprehension (faster than for loop):
>>> res_list = [ls1[i] * ls2[i] for i in range(len(ls1))]
OR
Numpy (fastest method) :
>>> import numpy as np
>>> ls1 = np.array([1,2,3,4])
>>> ls2 = np.array([2,1,6,5])
>>> res = ls1 * ls2
>>> print(res)
array([2,3,18,20])
OR
for loop (slowest but easily readable) :
res= []
for i in range(len(a)):
res.append(ls1[i]*ls2[i])
print(res)
Edit:
Kindly check this speed performance graph from freeCodeCamp
If you're looking for a one-liner, you can use list comprehension for this:
C = [x*y for x, y in zip(A, B)]
References:
zip()
List comprehension
Here are two ways to do it:
The more "Pythonic" way to do it is list comprehension:
A = [1, 2, 3]
B = [4, 5, 6]
C = [a * b for a, b in zip(A, B)] # [4, 10, 18]
Another way is to iterate on both of the lists with the function zip():
A = [1, 2, 3]
B = [4, 5, 6]
C = []
for a,b in zip(A, B):
result = a * b
C.append(result)
# C = [4, 10, 18]
Good Luck!

Mutability of lists in python

Example one: Changing the value that has been appended to b changes the value in the original list l
>>> l = [1 , 2, 3]
>>> b = []
>>> b.append(l)
>>> b[0].append(4)
>>> b
[[1, 2, 3, 4]]
>>> l
[1, 2, 3, 4]
Example 2: l1 is appended to ans and then the value of l1 is modified. However, the value in ans remains the same.
>>> l1 = [1, 2, 3]
>>> ans = []
>>> ans.append(l1)
>>> ans
[[1, 2, 3]]
>>> l1 = [2, 3, 4]
>>> ans
[[1, 2, 3]]
I seem to be missing some fundamental point about the mutability of lists. Could someone please point it out?
You are not mutating l1. You are assigning a new object to the same name, which makes that name point to a new object. You are moving a label, not modifying an object. The only remaining reference to the list that l1 used to point to is now ans[0].
In your first example, l is a pointer, as well as b.
l is then appended to b, so b[0] now refers to the pointer.
Next, you append 4 to b[0], which is the same thing as l, so 4 is added to both b[0] and l.
In your second example, ans contains the pointer of l1, just like b contained the pointer of l
Then, you changed l1 itself by assigning it to a different array, so l1 changed but ans[0] did not.
The biggest takeaway from this is that append just changes the list, and the pointer remains the same. But when you set a variable to a different list, the pointer changes.
Replace
>>> l1 = [2, 3, 4]
with
>>> l1[:] = [2, 3, 4]
That will not assign a new list to l1.

split list into 2 lists corresponding to every other element

This question already has answers here:
Extract elements of list at odd positions
(5 answers)
Closed yesterday.
I know there are many chunky ways to do this, but I am looking for a slick pythonic way to accomplish the following. Given a list of numbers:
a = [0,1,2,3,4,5,6,7,8,9]
split this list into 2 lists corresponding to every other element:
b = [0,2,4,6,8]
c = [1,3,5,7,9]
You want:
b = a[::2] # Start at first element, then every other.
and:
c = a[1::2] # Start at second element, then every other.
So now we have what we want:
>>> print(b)
[0, 2, 4, 6, 8]
>>> print(c)
[1, 3, 5, 7, 9]
You can do that using list slicing:
b = a[::2]
c = a[1::2]
Example
>>> a = [0,1,2,3,4,5,6,7,8,9]
>>> b = a[::2]
>>> c = a[1::2]
>>> print b
[0,2,4,6,8]
>>> print c
[1,3,5,7,9]
The [::] syntax is as follows: [start:end:step]. If you don't specify any parameters for start and end, it will work with the whole list. Therefore, what the code above is doing is:
For b: start at index 0, take every other element from a
For c: start at index 1, take every other element from a
Try This :
a = [0,1,2,3,4,5,6,7,8,9]
>>> b=[i for x,i in enumerate(a) if x%2==1]
>>> c=[i for x,i in enumerate(a) if x%2==0]
>>> b
[1, 3, 5, 7, 9]
>>> c
[0, 2, 4, 6, 8]

python list index is the same list [duplicate]

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

Categories

Resources