Python list Not changing values [duplicate] - python

This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
x=[3,6,9,[12]]
y=list(x)
x[3][0]=50
x[1]=25
print(y)
The output of the code is [3, 6, 9, [50]]
Why did 12 change to 50, but 6 didn't change to 25?

When you do list(x), python makes a copy of the list x and stores it in y. So if it was a list with all elements as integers for example -:
x = [1, 2, 3, 4]
y = list(x)
x[0] = 7
print(x, y)
[7, 2, 3, 4] [1, 2, 3, 4]
You will notice no change in the 0th index of y, that is because the integers are stored and copied with the list.
Python generally stores values at different memory addresses and variables are like pointers that point to that address so the value can be fetched as and when needed.[Thanks for pointing this out in the comments of the question #ShobitTewari]
So a list for example is a reference to the list stored in memory [1, 2, 3, 4].
But if the list has a nested list in it like so -: [1, 2, [12]]
then this inner list [12] is also having its value at some other memory address and the index just points to that address. Unlike integers nested lists aren't stored at the same address as the rest of the list.
So when you do list(x), python copies the whole list into a new memory address more on that here. But if you have a nested list, then the memory address of that lists still stays the same.
So when you change the value of that nested list's 0th index, it changes it in the memory and the pointer of y still points to that old memory address, so value of the nested list changes.
x = [1, 2, 3, [4]]
y = list(x)
x[3][0] = 7
print(x, y)
[1, 2, 3, [7]] [1, 2, 3, [7]]

Related

How can I append items to a list without changing the original list [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
I have a list of lists that contain a list at the end. If this list has more than one element, I want to duplicate the entry and for each with the individual value without being in the list.
E.g.
[[1, [1,2]] -> [[1, 1][1, 2]]
There's probably a much more efficient solution than the one I've tried, but I'd like to understand why you're giving me the mistakes you're giving.
First, even though it indicates that it is not the same list, it is changing the value in both lists. Second, when I create the second element, it changes the previous one as well. Any explanation is welcome. Thanks
Variables in Python are just references. I recommend making a copy by using a slice. l_copy = l_orig[:]
When I first saw the question (pre-edit), I didn't see any code, so I did not have the context. It looks like you're copying the reference to that row. (Meaning it actually points to the sub-lists in the original.)
new_list.append(row[:])
Weird right? Look at the following example
lst1 = [1,2,3]
#bad copy example
_
lst2 = lst1
-
lst2.append(4)
print(lst1,lst2)
You would expect that only lst2 should have 4, but no. lst1 and lst2 both have 4.
[1, 2, 3, 4] [1, 2, 3, 4]
So to avoid a problem like this, we can use list2 = list1.copy()
lst1 = [1,2,3]
lst2 = lst1.copy()
lst2.append(4)
print(lst1,lst2)
output
[1, 2, 3] [1, 2, 3, 4]

understanding nested list from list with duplicated values [duplicate]

This question already has answers here:
How do I get the last element of a list?
(25 answers)
Closed 1 year ago.
To get [[1, 1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
from old_list = [1,1,2,2,3,3,3,4,4,4,4,5,5,5,5,5]
I found this answer:
new_list = []
for value in old_list:
if new_list and new_list[-1][0] == value:
new_list[-1].append(value)
else:
new_list.append([value])
I am trying to understand what is meaning of new_list[-1][0]
confusion came when I tried to run
new_list = []
new_list[-1] # shows index out of bounds
and new_list and new_list[-1][0] does not produce any error under if statement
What new_list[-1][0] is doing here.
new_list[-1][0] retrieves the last element of new_list, which is itself a list and gets its first element.
new_list and new_list[-1][0] == value short circuits, so it does not try to access the last element if the list is empty.
new_list[-1][0] is checking for the first value in the last element of the list new_list.
Example:
For
new_list = [[1, 1], [2, 2], [3, 3, 3], [4, 4, 4, 4], [5, 5, 5, 5, 5]]
if you try new_list[-1][0], you will get value 5.
[-1] gets you the last element of the list and [0] gives you the first value.
So, [-1] gets you [5,5,5,5,5] and then [0] gives yoou 5.
Say we tried something on a normal list like this.
new_list = [1,2,3]
print(new_list[-1][0])
We are going to receive an error
print(new_list[-1][0])
TypeError: 'int' object is not subscriptable
But if we try indexing that on lists of a list it will work.
new_list = [[1,2,3],[4,5,6]]
print(new_list[-1][0])
no error, output is
4
Lets take a look into list[-1][0]. Basically, [-1] will get us the last element in a list. In this case it will give us the last list in our bigger list. Then the [0] will get us the first element in a list. So the order is [4,5,6] & 4

Slicing a list with variable chunk size in Python [duplicate]

This question already has answers here:
Understanding slicing
(38 answers)
Closed 5 years ago.
I worked in Python 3.6, and I am a beginner. So can anyone give me a true way of how can slice a list into variable size sub-list. I tried this solution from this site, but it gave me fixed size of sliced list. To clarify:
if I have this list:
inputList= [0,1,2,3,4,5,6,7]
I want the output to be like e.g.:
outputList=[[0,1,2], [3,4], [5], [6,7]]
each time it depends on (for example) user input or some variable size.
Just use itertools.islice(). This has the added advantage that if you request a slice that you would normally take you out of bounds, you won't get an error. You'll just get as many items are left as possible.
>>> import itertools as it
>>> input_list = range(8)
>>> slices = (3, 2, 1, 2)
>>> iterable = iter(input_list)
>>> output_list = [list(it.islice(iterable, sl)) for sl in slices]
>>> output_list
[[0, 1, 2], [3, 4], [5], [6, 7]]
For example, if you had slices = (3, 2, 1, 3, 2), your result would be [[0, 1, 2], [3, 4], [5], [6, 7], []].
Basically, iter(input_list) creates an iterable of your list so you can fetch the next k values with islice().
You can do this in a loop making use of python's [:#] slice notation:
Let's say the user's input for slicing chunk sizes is stored in a list. They want chunks of 3, 2, 1 and 2, so the user input defining the chunks gets stored into a list that has has [3,2,1,2].
Then, loop through that list and use it to get your slices:
input_list = [0,1,2,3,4,5,6,7]
chunk_list = [3,2,1,2]
output_list = []
for i in chunk_list:
output_list.append(input_list[:i])
input_list = input_list[i:]
print(output_list)
Prints:
[[0, 1, 2], [3, 4], [5], [6, 7]]
Probably you just want to learn about slicing. See Understanding Python's slice notation
To get your example output, you could do
outputList = [inputList[:3], inputList[3:5], inputList[5:6], inputList[6:]]

Changing a list within dictionaries [duplicate]

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.
Why does the code below output {'a': [1, 3, 4, 5, 6, 7, 8, 9], 'b': [1, 3, 4, 5, 6, 7, 8, 9]}
adic = {}
main_array = [1,2,3,4,5,6,7,8,9]
adic["a"] = main_array
adic["b"] = main_array
array = adic["a"]
array.remove(2)
print(adic)
I am not even assigning the new array to a key. Why should 2 be automatically removed from all the arrays in the dictionary. Am i missing something vital?
All your references point to the same list, as you can check by adding:
print(id(adic["a"]))
print(id(adic["b"]))
print(id(array))
print(id(main_array))
On my system:
32707888
32707888
32707888
32707888
Assignment does not create a copy.
There are several ways to copy a list if this is what you want, such as
new_list = list(old_list)
discussed here.
The reason why your output is doing that is because of the lines where you set each adic['value'] = main_array each of those statements is pointing to the same memory address of your main_array so when you do array = adic["a"] that's also pointing to the same memory address and when you remove 2 it's removing 2 from main_array. Because you are removing from main_array, everything that pointed to main_array is also affected.

Can lists be mutated? [duplicate]

This question already has answers here:
Are lists mutable? [duplicate]
(6 answers)
Closed 7 months ago.
When I type following code,
x=[1,2,4]
print(x)
print("x",id(x))
x=[2,5,3]
print(x)
print("x",id(x))
it gives the output as
[1, 2, 4]
x 47606160
[2, 5, 3]
x 47578768
If lists are mutable then why it give 2 memory address when changing the list x?
You created a new list object and bound it to the same name, x. You never mutated the existing list object bound to x at the start.
Names in Python are just references. Assignment is binding a name to an object. When you assign to x again, you are pointing that reference to a different object. In your code, you simply created a whole new list object, then rebound x to that new object.
If you want to mutate a list, call methods on that object:
x.append(2)
x.extend([2, 3, 5])
or assign to indices or slices of the list:
x[2] = 42
x[:3] = [5, 6, 7]
Demo:
>>> x = [1, 2, 3]
>>> id(x)
4301563088
>>> x
[1, 2, 3]
>>> x[:2] = [42, 81]
>>> x
[42, 81, 3]
>>> id(x)
4301563088
We changed the list object (mutated it), but the id() of that list object did not change. It is still the same list object.
Perhaps this excellent presentation by Ned Batchelder on Python names and binding can help: Facts and myths about Python names and values.
You did not mutate (change) the list object referenced by x with this line:
x=[2,5,3]
Instead, that line creates a new list object and then reassigns the variable x to it. So, x now references the new object and id(x) gives a different number than before:
>>> x=[1,2,4] # x references the list object [1,2,4]
>>> x
[1, 2, 4]
>>> x=[2,5,3] # x now references an entirely new list object [2,5,3]
>>> x
[2, 5, 3]
>>>
You are not mutating the list, you are creating a new list and assigning it to the name x. That's why id is giving you different outputs. Your first list is gone and will be garbage-collected (unless there's another reference to it somewhere).

Categories

Resources