Below is non-working and working code which generates a list of lists.
Example 1 does not work correctly, it repeats the last list appended over and over.
Example 2, where I replaced delete with creating a new list does work correctly.
# Example 1, this does not work correctly
l1 = []
l2 = []
x = 0
for n in range(0,3):
del l1[:] # deleting all list elements
for i in range(0,3):
l1.append(x)
x+=1
l2.append(l1)
print(l2)
# Example 2, this works correctly
l2 = []
x = 0
for n in range(0,3):
l1 = [] # creating the list each loop through
for i in range(0,3):
l1.append(x)
x+=1
l2.append(l1)
print(l2)
In your first example, l1 is the same list object the entire time. When you do l2.append(l1), you insert a reference to this l1 object into l2. When the loop restarts and you delete everything in l1, you also delete everything in the list inside l2, because that is the same list. You are appending the same list object to l2 multiple times, so every time you clear it, you clear every list in l2.
In the second example, you create a separate list object every time. Each list object is thus independent, and clearing one doesn't affect the others.
Visualization of #1 code - http://goo.gl/6ICqo
l2 and l1 refer to the same object (list). When you delete all the elements of the list, the change is reflected in l2 and l1.
Visualization of #2 code - http://goo.gl/fkoqh
Here, when the code executes l1 = [], l1's reference gets re-assigned. But l2's elements keep referring to the original object.
Related
So the question is to delete an element at position i in a list, what are the differences between the following actions?
i = 3
l = [0,1,2,3,4,5]
del l[i]
i = 3
l = [0,1,2,3,4,5]
l = l[:i] + l[i+1:]
Both ways give the list the same result. But what are the essential differences?
Why is the second operation not acceptable?
But what are the essential differences?
The del way modifies the list in place. This means that any other names for that list will have the change reflected:
i = 3
l = [0,1,2,3,4,5]
k = l
del l[i]
# k has changed
The id() of the list does not change, because it is still the same list - only its contents have changed (just like if you used e.g. .append or .pop, or assigned to an element).
The slicing way creates a new list. This means that other names for the list will not have the change reflected - because they are still names for the original list, and that list was never changed.
i = 3
l = [0,1,2,3,4,5]
k = l
l = l[:i] + l[i+1:]
# k has not changed
If there are no other names for the original list, then the slicing way allows for the original list to be garbage-collected. The new list will probably not have the same id() as the original, because the old list's contents have to stick around during construction of the new one. There will be a temporary spike in the amount of memory used, which may matter for some programs with millions of elements in the list (or with elements that are very large objects).
If there are other names for the original list, then the new list will have a different id(), because it is a different list and the original still exists.
So the question is to delete an element at position i in a list
not
"to create another list without element i". That's why the second operation is not acceptable
I was doing some exercises in python python and I bumped into a problem. I already printed a list reversed and I wanted to print the reversed elements in separate lines too but for some reason it only prints the first one and if I put the first print into comment it prints out the loop just fine. Why?
def main():
pass
if __name__ == '__main__':
main()
list1 = [10, 20, 30, 40, 50]
def reverse_list(l1):
l2 = []
for i in range(len(l1)):
l2.append(l1.pop())
return l2
print(reverse_list(list1))
pass
def reverse_print(l):
listr = reversed(l)
for j in listr:
print(j)
reverse_print(list1)
print("Complete...")
In python, data types are divided into mutable and immutable types:
Mutable object: the value in the memory pointed to by the object can be changed
Immutable object: The value in the memory pointed to by the object cannot be changed, so when the value pointed to by the variable changes, it is equivalent to copying the original value and storing it in a new address, and the variable points to this new address.
a = [1,2,3,4]
a_ref = a
print(a) # [1,2,3,4]
a_ref[0] = 5
print(a) # [5,2,3,4]
It can be seen from the above code
a, a_ref are exactly the same
a and a_ref have the same memory location
modification to a_ref, a will also be changed
for example:
a = [1,2,3,4]
def somefunc(a2):
a2.append(5)
print(a) # [1,2,3,4]
somefunc(a)
print(a) # [1,2,3,4,5]
Normally, it won't change a by calling somefunc(a)
BUT
Since a2 is a reference to a and points to the same memory location, when a2 is modified, it will also be modified to a
in your code:
when you calling reverse_list(list1), l1 is a reference to list1, when you pop the element from l1, it will also pop the element in list1
so after called reverse_list(list1), list1 is empty, that why reverse_print(list1) do not print anything
Sollution
def reverse_list(l1):
l1_copy = l1[:] # copy the whole list
l2 = []
for i in range(len(l1_copy)):
l2.append(l1_copy.pop())
return l2
when you call l1_copy = l1[:]
than l1_copy won't point to same memory location
so l1 and list1 won't modified when modifica l1_copy
PS: english is my second langage, so there maybe have some gramma mistake, please excuse me
at the second print list1 has been emptied out from using the pop() method in reverse_list.
to reverse a list perhaps you should use the reverse()method like the following example:
List1 = [1,2,3]
List1.reverse()
print(List1) # [3,2,1]
Basically, given a list l of letters, i wanted to filter a list of letters to include only one instance of said letters in a new list:
l2 = []
for i in l:
if i not in l2:
l2.append()
And i wanted to use list comprehension, so i wrote:
l2 = [i for i in l if i not in l2]
But it returns me an empty l2. I'm just starting to learn how to use list comprehension and i'm kinda tired so i can't see where or if i'm doing wrong :(
list comprehension will not be working in this case as it works on a saved state of variable.
So, earlier l2 was blank and that state would be considered in comprehending.
Hence, the output would contain all the elements.
What i could notice is you were trying to get unique elements of 'l'.
Either you can use,
l2 = set(l) # if rlist is required you can type cast it back to list like, l2 = list(set(l))
The list-comprehension here can't work, as l2 is updated only when the all list-comprehension stuff is done, there no idea of list-comp intermediate state
What you want is just a unique instance of each letter, in other words : a set
l2 = set(l)
l2 = list(set(l)) # if you really want a list at the end
The problem with your list comprehension is that it relies on the list l2, which itself is the target of the list comprehension.
Sometimes a list comprehension is not the best way to go, even though it is a nice tool.
For your purpose it is best to convert list l to a set (which does not have duplicates) and then convert back to a list, which can be assigned to your list l2:
l2 = list(set(l))
I have written the python code in the following form
temp=[]
x=[1,2,3]
for i in range(4):
temp=temp+[x]
temp[1][1]=x[1]+1
print temp[0]
print temp[1]
Here, I wanted the value of just temp[1][1], but the value of temp[0][1] also gets changed. Is there a way of changing just one value? I created a new list and tried to add it to temp, but that does not seem to work as well.
Update:
Thanks, but it did not seem to work in my case (which was a multi dimensional array). I have the code has follows:
tempList=[]
for i in range(openList[0].hx):
tempList=tempList+[copy.copy(abc)]
tempList[0][0][0]=123
print sudokuList
Here abc is a two dimensional list. Modifying the value of tempList[0][0][0] changes the value of tempList[1][0][0] and so on.
That's because of that you are assigning the x to all of your list items so all of them are references to one object and once you change one on them actually you have changed all of them. for getting ride of this problem you can use a list comprehension to define the temp list :
temp=[[1,2,3] for _ in range(4)]
temp[1][1]=7
print temp[0]
print temp[1]
result :
[1, 2, 3]
[1, 7, 3]
This is actually a common error for beginners to Python: How to clone or copy a list?
When you add x to temp four times, you're creating a temp which has the same x four number of times.
So, temp[0], temp[2], temp[3] and temp[4] are all pointing to the same x you declared at the first line.
Just make a copy when adding:
temp=[]
x=[1,2,3]
for i in range(4):
temp=temp.append(x[:])
temp[1][1]=x[1]+1
print temp[0]
print temp[1]
You can see it with id function, which returns a different value for different objects:
>>> temp=[]
>>> x=[1,2,3]
>>> for i in range(4):
... temp=temp+[x]
...
>>> id(temp[0]), id(temp[1])
(4301992880, 4301992880) # they're the same
>>> temp=[]
>>> x=[1,2,3]
>>> for i in range(4):
... temp=temp+[x[:]]
...
>>> id(temp[0]), id(temp[1])
(4301992088, 4302183024) # now they are not
Try, the following. x in for loop is a reference to the original x and not a copy. Because of this reference, changing any element reflects on all objects. So you would need to make a copy as used in following snippet.
temp=[]
x=[1,2,3]
for i in range(4):
temp=temp+[x[:]]
temp[1][1]=x[1]+1
print temp[0]
print temp[1]
----EDIT----
As per your comment, use copy.deepcopy to copy the list. deepcopy would recursively copy all the referenced elements inside the list. Check copy.deepcopy. So the code looks like:-
import copy
temp=[]
x=[1,2,3]
for i in range(4):
x_copy = copy.deepcopy(x)
#do something with x_copy. use this inplace of x in your code.
#will work for 1D or 2D or any other higher order lists.
``I have a dictionary in python like this.
dictionary = {"00":[1,2,3,4,5,6,7,8,9],"01":[1,2,3,4,5,6,7,8,9],"02":[1,2,3,4,5,6,7,8,9],"03":[1,2,3,4,5,6,7,8,9],"04":[1,2,3,4,5,6,7,8,9]........up-to "99":[1,2,3,4,5,6,7,8,9]}
I have to delete the value 2 from the list of "00".I tried it using following statement.
del (dictionary[key][dictionary[key].index(sudokumatrix[i][iindex])]).
Here key has value "00" and sudokumatrix[i][iindex] has value 2.But i got resulting dictionary as
{"00":[1,3,4,5,6,7,8,9],"01":[1,3,4,5,6,7,8,9],"02":[1,3,4,5,6,7,8,9],"03":[1,3,4,5,6,7,8,9],"04":[1,3,4,5,6,7,8,9].....}.
I have to get the result as:
{"00":[1,3,4,5,6,7,8,9],"01":[1,2,3,4,5,6,7,8,9],"02":[1,2,3,4,5,6,7,8,9],"03":[1,2,3,4,5,6,7,8,9],"04":[1,2,3,4,5,6,7,8,9]....}
I am posting the whole code here:
dictionary = dict()
zerotonine = "123456789"
list2 = list(zerotonine)
list2 = [int(i) for i in list2]
sudokumatrix=[]
for p in range(9):
for q in range(9):
keyis=str(p)+str(q)
dictionary[keyis] = list2
for i in range(9):
initialinput = [1,2,3,4,5,6,7,8,9]
list1=list(initialinput)
list1 = [int(i) for i in list1]
sudokumatrix.append(list1)
key = "00"
del dictionary[key][dictionary[key].index(sudokumatrix[0][1])]
print dictionary
EDIT == I guess(since the generation of dictionary is not given) ==EDIT.
The reason is that the values of keys '00', '01', ... are pointing to the same list. Modifying one of them will definitely affect the others.
Try using this to generate your dict
dictionary = dict((str(x).zfill(2), range(1, 10)) for x in range(100))
Your code of this part is actually not wrong, but to use list.remove() will make it much better.
The issue has to do with pointers.
replace this:
dictionary[keyis] = list2
with this:
dictionary[keyis] = [int(i) for i in list2]
You're creating list2 correctly, but when you go into the loop Python doesn't make a brand new copy of it with every iteration. It makes a pointer to the original list. Python sees:
dictionary[keyis] = list2
and says "oh, list2? I recognize that name! I have that as an object in memory already! I'll save some space by just updating the original copy and linking it here! Any time someone wants to view it or update it I'll just deal with the original and everything will be awesome forever!!!"
OK, so maybe the python interpreter isn't that enthusiastic, but that's how I like to think of it. The end result is that all of your dictionary values are pointing at the original list.
If you don't mind deleting every occurrence of 2 in the list, you can use list comprehension:
dictionary["00"] = [i for i in dictionary["00"] if i != 2]
This will create a new list, and will avoid altering the other values, as it appears all your dictionary values reference the same list.
EDIT: Yep your dictionary values reference the same list
you could use dictionary and list comprehension to create your dictionary
dictionary = {str(x):[i for i in range(10)] for x in range(100)}