Why are these two arrays the same? [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 2 years ago.
I want to have a copy of my list, and then sort it, but due of the way that python works, if i sort the copy of the list, it sort also the original list. Here is my code:
def swapBySoting(arr):
newArr = arr
newArr.sort()
swap = 0
for i in range(len(arr)):
if arr[i] != newArr[i]:
swap +=1
return int(swap / 2)
I only need to know how to store the copy in another reference of memory, to sort only the copy. Thanks

Assignment just creates a new alias of an object, it doesn't perform a copy. You have two simple solutions:
Shallow copy the first list when assigning to the second:
newArr = arr[:] # Or arr.copy()
Combine your copy and sort into a single step with the sorted built-in (that creates a new list, sorts it, and returns the new list):
newArr = sorted(arr) # No need to call .sort() afterwards
Side-note: For comparing elements, looping over indices is relatively slow and unpythonic. Using zip and unpacking to useful names gets the much nicer (and a titch faster):
for old, new in zip(arr, newArr):
if old != new:
swap +=1
That said, this algorithm for counting minimum swaps is almost certainly wrong, but that's another question entirely.

Related

Sorting a list using for loop in python [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
How to remove items from a list while iterating?
(25 answers)
Closed 12 months ago.
I was trying to sort a list using for loops in python.
I wrote the code like this.
L=[1,2,3,6,7,9,4]
NL=[]
for i in L:
NL.append(min(L))
L.remove(min(L))
print(NL)
But here the output is [1, 2, 3, 4].
I can't understand why the output is stopping at 4. I am new to coding. It would be helpful if someone could help me with this.
You're removing elements from a list while looping over it, which is problematic (if the index of the element you're removing is before your current loop index, the "next element" being shifted back by one won't be visited). As you don't need to work with the index anyways, you can simply loop n times, where n is the number of elements in the list (the length of the list):
L=[1,2,3,6,7,9,4]
NL=[]
for _ in range(len(L)):
NL.append(min(L))
L.remove(min(L))
print(NL)
Side note: The algorithm you've implemented is called "selectionsort" and has quadratic time complexity. You're also emptying the input list. In practice, you should usually be using Python's builtin [...].sort() to sort the input list in place; if you want a sorted copy, you can always call [...].copy() first.

Changing list while iterating [duplicate]

This question already has answers here:
Modifying a list while iterating over it - why not? [duplicate]
(4 answers)
Closed 6 years ago.
I've found a python puzzle and can't find out why it works.
x = ['a','b','c']
for m in x:
x.remove(m)
and after this loop x = ['b'].
But why?
As far as I understand for keyword implicitly creates iterator for this list. Does .remove() calls __next__() method so b is skipped? I can't find any mentions of it but this is my best guess.
Here you are iterating over the original list. On the first iteration, you removed the 0th index element i.e. a. Now, your list is as: ['b','c']. On the second iteration your for loop will access the value at index 1 but your index 1 has value c. So the c is removed. Hence resultant list will be ['b'].
In order to make it behave expectedly, iterate over the copy of the list, and remove the item from original list. For example:
x = ['a','b','c']
for m in list(x): # <-- Here 'list(x)' will create the copy of list 'x'
# for will iterate over the copy
x.remove(m)
# updated value of 'x' will be: []
Note: If it is not for demo purpose and you are using this code for emptying the list, efficient way of emptying the list will be:
del x[:]

How to get a copy from a 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 9 years ago.
I am trying to get an element from list and make some change on this element (which is also a list). Weirdly, the change applied on the previous list. Here is my code:
>>>sentences[0]
['<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>']
>>>sentence = sentences[0]
>>>sentence.insert(0,startc); sentence.append(endc)
>>>sentences[0]
['<s>/<s>',
'<s>/<s>',
'I/PRP',
'need/VBP',
'to/TO',
'have/VB',
'dinner/NN',
'served/VBN',
'</s>/</s>'
'</s>/</s>']
It is like I just got a pointer to that element, not a copy
You do get a "pointer", in fact. Lists (and any mutable value type!) are passed around as reference in Python.
You can make a copy of a list by passing it to the list() object constructor, or by making a full slice using [:].
a = [1,2,3]
b = a
c = list(a)
d = a[:]
a[1] = 4 # changes the list referenced by both 'a' and 'b', but not 'c' or 'd'
You're exactly right! In Python, when you pass a list as an argument to a function, or you assign a list to another variable, you're actually passing a pointer to it.
This is for efficiency reasons; if you made a separate copy of a 1000-item list every time you did one of the aforementioned things, the program would consume way too much memory and time.
To overcome this in Python, you can duplicate a one-dimensional list using = originalList[:] or = list(originalList):
sentence = sentences[0][:] # or sentence = list(sentences[0])
sentence.insert(0,startc)
sentence.append(endc)
print(sentence) # modified
print(sentences[0]) # not modified
Consider using list comprehension if you need to duplicate a 2D list.

Deleting list elements whilst iterating over it [duplicate]

This question already has answers here:
How to remove items from a list while iterating?
(25 answers)
Closed 10 years ago.
I need to delete elements from a list whilst iterating over it (I cannot create a new list as it is referenced in code I have no control over).
The best I've come up with is:
last_index = len(somelist) - 1
for (index,item) in enumerate(reversed(somelist)):
if somecondition(item):
del somelist[last_index - index]
Are there better alternatives? I've seen this post and this one too, but none of the solutions provided are as efficient or as concise (IMHO).
You can use a list comprehension + slice assignment, which is certainly more concise -- I don't know about efficiency (although I would expect it to do better in that regard as well since you don't need to keep shifting elements in the list over every time you delete an item ...)
somelist[:] = [ x for x in somelist if not somecondition(x) ]

python a=[[],]*10 [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python list confusion
When I write a simple python script, I define a new list as follows:
A=[[],]*10
What I wanna do is just initialize a list whose length is 10 and each element is a empty list.
And when I do something like:
A[0].append(["abc",])
I just wanna append this ["abc",] to A[0], and it turn out to be that every elements in A is appended with ["abc",]
I know this probably due to my initialization (A=[[],]*10) . I just want to know why this happened.
Your expression A=[[]]*10 is equivalent to:
a = []
A = [a]*10
This means that A consists of 10 references to one and the same list.
You are creating a list with 10 references to the same empty list.
You should use a list comprehension instead:
A = [[] for _ in range(10)]
In a list comprehension, you create a new list for every iteration through the loop. If you are using python 2, you should use xrange instead of range (although with only 10 elements that won't make much difference).
All the empty lists are references to the same object.

Categories