Understanding the shallow copy in Python [duplicate] - python-3.x

This question already has answers here:
What is the difference between shallow copy, deepcopy and normal assignment operation?
(12 answers)
Closed 2 years ago.
I have two sets of code which demonstrate shallow copy but I am not able to explain why the code behaves differently.
The first set of code:
import copy
cv1 = [1,2,3]
cv2 = copy.copy(cv1)
print(cv1)
print(cv2)
cv2[0] = 0
cv1[1] = 1
print(cv1)
print(cv2)
The output :
[1, 2, 3]
[1, 2, 3]
[1, 1, 3]
[0, 2, 3]
Second set of code:
import copy
a = [ [1, 2, 3], [4, 5, 6] ]
b = copy.copy(a)
print(a)
print(b)
a[1][2] = 25
b[0][0] = 98
print(a)
print(b)
The output :
[[1, 2, 3], [4, 5, 6]]
[[1, 2, 3], [4, 5, 6]]
[[98, 2, 3], [4, 5, 25]]
[[98, 2, 3], [4, 5, 25]]
In my understanding, both codes should do the exact same thing. Why is that after the second set of print statements in each code snippet, the contents of cv1 and cv2 are different while a and b are the same.? Maybe it is a very basic error on my side, I am new to Python, but I can't seem to figure this out. Any help is appreciated.

This has to do with the copy library you imported.
copy.copy(x)
Return a shallow copy of x.
A shallow copy constructs a new compound object and then (to the extent possible) inserts > references into it to the objects found in the original.
So in the first case the copy is creating a new list of int object while the second case it is creating a list of references object.
While in the second case the list a and b are different, they contain the same lists inside. Thats why changing one of those list inside will edit both lists.
For the two cases to be the same you need to use the copy.deepcopy function.

Related

How to create a list of arrays from multiple same-size vectors

I am attempting to create a list of arrays from 2 vectors.
I have a dataset I'm reading from a .csv file and need to pair each value with a 1 to create a list of arrays.
import numpy as np
Data = np.array([1, 2, 3, 4, 5]) #this is actually a column in a .csv file, but simplified it for the example
#do something here
output = ([1,1], [1,2], [1,3], [1,4], [1,5]) #2nd column in each array is the data, first is a 1
I've tried to use numpy concatenate and vstack, but they don't give me exactly what I'm looking for.
Any suggestions would be appreciated.
You can form the output using a list comprehension:
data = [1, 2, 3, 4, 5]
output = [[1, item] for item in data]
This will output:
[[1, 1], [1, 2], [1, 3], [1, 4], [1, 5]]

How do I flatten a list containing both values and other lists? [duplicate]

This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 1 year ago.
For instance, I could have this list:
l = [1, [2, 3], [4, 5, [6, 7], 8]]
and I want to flatten the list like this:
l = [1, 2, 3, 4, 5, 6, 7, 8]
I found some methods online for doing this, but they assume that the list doesn't contain any values outside of sub-lists, or have side effects like reversing the order of elements. What's the best way to do this?
[Edit] I got an existing question recommended, but I couldn't understand what "yield from" does in Python, as I haven't seen it before in that context.
# initializing the data and empty list
data = [1, [2, 3, [4, 5]], 6, [[7], [8, 9]]]
flat_list = []
# function
def flatten_list(data):
# iterating over the data
for element in data:
# checking for list
if type(element) == list:
# calling the same function with current element as new argument
flatten_list(element)
else:
flat_list.append(element)
# flattening the given list
flatten_list(data)
# printing the flat_list
print(flat_list)
(See more at https://geekflare.com/flatten-list-python/)

I'm trying to add lists in lists by column. Is there a way to sum them with missing variables in a list?

I had followed the book and can sum lists in lists by column but one of the test cases is missing variables in the list and I'm unable to move forward because I keep getting an index error.
The first initial_list works as it should giving [3,6,9]
The second one though should apparently give me [3,4,9,4]
list_initial = [[1, 2, 3], [1, 2, 3],[1, 2, 3 ]]
list_initial = [[1, 2, 3], [1], [1, 2, 3, 4]]
def column_sums(list_initial):
column = 0
list_new = []
while column < len(list_initial):
total = sum(row[column] for row in list_initial )
list_new.append(total)
column = column + 1
print(list_new)
column_sums(list_initial)
You can effectively "transpose" your data so that rows become columns, and then use itertools.zip_longest with a fillvalue of 0, to sum across them, eg:
from itertools import zip_longest
list_initial = [[1, 2, 3], [1], [1, 2, 3, 4]]
summed = [sum(col) for col in zip_longest(*list_initial, fillvalue=0)]
# [3, 4, 6, 4]

What is the pythonic way of extracting (& removing) a slice from a list? Or... What is the "inverse" of the slice+=list operator - python

I know how insert a list into a list, "slice+=list" ...
master=[0,1,2,3,7,8,9]
master[:4]+=[4,5,6] # insert 4,5,6
(crudely) The inverse of this operation is removing a slice 4:7 from the list, I tried:
extracted=del master[4:7]
But this gives a syntax error "SyntaxError: invalid syntax".
Likewise the inverse slice operator "-=" doesn't appear to exist.
As a workaround I have used the following:
extracted=master[4:7]; del master[4:7]
This "works" and the "extracted" is the subslice removed from "master", e.g.
print dict(master=master,extracted=extracted)
Output:
{'extracted': [4, 5, 6], 'master': [0, 1, 2, 3, 7, 8, 9]}
Is there a better/pythonic/simpler way ?
In particular I don't like the repeated [4:7] in:
extracted=master[4:7]; del master[4:7]"
Because of potential side-effects: eg
extracted=master[randint(0,3):randint(7,10)]; del master[randint(0,3):randint(7,10)]
i.e. the following reads much better, and would have no "side-effects"...
extracted=del master[randint(0,3):randint(7,10)]
Any hints? Is there a slice "-=" operator I could have used to invert the action of the slice "+=" operator?
Your best bet is to use a slice:
-> s = slice(4, 7)
-> master
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
--> extracted = master[s]
--> extracted
[4, 5, 6]
--> del master[s]
--> master
[0, 1, 2, 3, 7, 8, 9]
It still requires two commands, but you can use a single object to respresent the piece you want.
For me the cleaner option is as follows:
>>> L=[1,2,3,4,5,6] #Define the list
>>> L #Check it
[1, 2, 3, 4, 5, 6]
>>> extract= L[3:6] ; L[3:6]=[] #Assign the slice to 'extract'; delete the slice
>>> L #Items removed from the list
[1, 2, 3]
>>> extract #And assigned to extract
[4, 5, 6]
Cheers!

How to multiply elements in the list in Python

I've found answers that tackle the question of how to multiply with the element value, but what concerns me is how to make copies of the element itself. I have:
a = [1, 2, 3]
x = 3
b = []
I tried:
b.append(a * x)
But that gives me:
[1, 2, 3, 1, 2, 3, 1, 2, 3]
and I need:
b = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
Please note I'm a programming novice. Thanks!
If you need to copy the list and not a reference to the list, you can't use *.
b = [a[:] for i in range(x)]
(a[:] creates a copy of the list.)

Resources