+ 2

Why is un2 an empty array ?

I created what i believed was a simple code to sort an array "A test" but discovered my un2 was empty when I was going to do a "B test". I started by creating array 'un' and my second array was a copy of 'un' as 'un2' ``` un = [91,82,43,54,36,67,28,19,101,70] un2 = un # Create a copy of un print("us2:",un2) print("us:",un) na = [] for i in range(len(un)): x = min(un) na.append(x) un.remove(x) print("sa:",na) print("us2:",un2) #beginning of "B test" ``` What happened un2 is empty ?

13th Oct 2024, 4:09 PM
BroFar
BroFar - avatar
15 Answers
+ 10
other ways of making shallow copy: un2 = un[:] un2 = list(un) un2 = [*un] for nested lists, you will need to use the copy module using copy.deepcopy()
13th Oct 2024, 5:42 PM
Bob_Li
Bob_Li - avatar
+ 6
The following explanation can be seen in my code sample here: https://www.sololearn.com/en/compiler-playground/cPOCEjMhk6tj When you edit the values inside UN, those are the same values for UN2. un and un2 are both pointing to the same data in memory. For example. un = [1,2,3] un2 = un print(un) print(un2) Both are the same output. Then try this: un = [1,2,3] un2 = un un[0] = 4 print(un) print(un2) Both still output the same thing. Now try this: un = [1,2,3] un2 = un un = [4,5,6] print(un) print(un2) These will output different results. The reason why has to do with understanding there are two things going on with the variables. Each variable is technically a pointer. un and un2 are two variables, but point to the same data in memory. The data is the list [1,2,3]. This is in one location in memory but pointed to by two different pointers, un and un2. If you create a new list [4,5,6] and point un to that, you end up with un = [4,5,6] and un2 = [1,2,3] If you want un and un2 to have different copies of the data, you can do that like this: un = [1,2,3] un2 = un.copy() un[0] = 4 print(un) print(un2) The .copy() will replicate the data into a new list so you can update un without affecting un2.
13th Oct 2024, 4:25 PM
Jerry Hobby
Jerry Hobby - avatar
+ 6
BroFar I'm not sure which method is better. For short lists, I guess it doesn't matter. I like the brevity of the slice method [:], but Vitaly Sokol's *un2, is shorter by one character 😎. Jerry Hobby 's suggestion to use .copy() method is the most easily understandable and is probably the best choice for codes that's going to be shared with other people.
14th Oct 2024, 1:48 AM
Bob_Li
Bob_Li - avatar
+ 5
SoloProg lists being a reference type is sometimes useful. Mutating the items become more efficient. Just have to remember not to use = to duplicate them.
13th Oct 2024, 5:58 PM
Bob_Li
Bob_Li - avatar
+ 4
un2 shares the same reference as un in memory – un2 is just another alias for the existing un.
13th Oct 2024, 4:59 PM
Lisa
Lisa - avatar
+ 4
I learned a lot of languages. So i confuse the syntax, so i sometimes need to research the correct code. (⌐■_■)
13th Oct 2024, 6:55 PM
SoloProg
SoloProg - avatar
+ 4
Hum ... just a follow-up on my question of hierarchy Bob_Li and thank you for explanation. Choose the syntax based on your specific needs: Creating a shallow copy of a list: Use [:] or .copy(). Converting an iterable to a list: Use list(un). Unpacking elements from an iterable: Use [*un] Then there is deepcopy() # import copy ... copy.deepcopy(un) Creates a deep copy, which recursively copies nested objects as well. Use Case: When you need to copy objects with nested structures (e.g., nested lists, dictionaries) and avoid modifying the original object.
14th Oct 2024, 2:32 AM
BroFar
BroFar - avatar
+ 3
Also works for shallow copy use: *un2 , = un [*un2] = un
13th Oct 2024, 8:59 PM
Vitaly Sokol
Vitaly Sokol - avatar
+ 3
BroFar , just for completness: in case we wanted to check if 2 objects are the `same` we can use the `id()` built-in function. see the code sample in the attached file: https://sololearn.com/compiler-playground/c7NmW72ILmDZ/?ref=app
15th Oct 2024, 9:43 AM
Lothar
Lothar - avatar
+ 2
This is why i hate python /j ¯\_(ツ)_/¯
13th Oct 2024, 5:49 PM
SoloProg
SoloProg - avatar
+ 2
SoloProg same here and forgetting something as [:] or .copy() or [*var] makes sense
13th Oct 2024, 7:03 PM
BroFar
BroFar - avatar
+ 1
Thanks everyone Bob_Li / Lisa / Jerry Hobby 😆 SoloProg yup I didn't exactly copy the 'un' to 'un2' ... forgetting that what happens to 'un' would directly effect 'un2' was emptied as I removed elements from 'un' - good catch. A dah moment: The reason why un2 is empty in your code is because you're modifying the original array un within the loop. When you create un2 as a copy of un, both arrays initially reference the same underlying data. However, when you remove elements from un inside the loop, those changes are reflected in both un and un2 since they share the same data.
13th Oct 2024, 6:04 PM
BroFar
BroFar - avatar
+ 1
Bob_Li is the a hierarchical reason to use each: • [:] • list(un) • [*un] • .copy()
13th Oct 2024, 7:23 PM
BroFar
BroFar - avatar
+ 1
If you want to sort a list of un and store it in un2 unchanged, you can load it from Python's .sort() or sorted() functions x2 = x.copy() or x2 = sorted(x)
26th Oct 2024, 6:54 PM
CodeStory
CodeStory - avatar
0
To follow on from @Bob_Li, it would be a good idea to get down the basics of mutable/immutable objects, and the concept of deep and shallow copy. <sarcasm>Spoiler alert</sarcasm> * The difference between mutable and immutable objects is that a mutable object can be changed, but an immutable one cannot. * A shallow copy makes a copy of an object, but where each attribute is another mutable object it is a reference to that same object whereas a deep copy copies all of those objects. For more detail see https://docs.python.org/3/library/copy.html which involves a standard library module (ICYMI it is built into python but needs to be imported). I would probably go with the [:] version as a shortcut to make shallow copies, however lists have a copy method that returns a shallow copy of the list.
17th Oct 2024, 5:32 AM
Jonathan Shiell