I am working on recursion and I have a problem that I have solved but I would like to know what is going on and why the way I tried first does not work. The only issue I have is emptying the listOfX when it has a length of 3.
Here is the original code that does not work as expected:
sol = []
def recLoop(levelWidth,levelOn,listOfX):
if len(listOfX) == 3:
sol.append([listOfX[0],listOfX[1]])
sol.append([listOfX[0],listOfX[2]])
listOfX = [] #THIS DOES NOT WORK
print listOfX
if len(levelWidth) != levelOn:
for x in range(levelWidth[levelOn]):
listOfX.append(x)
recLoop(levelWidth,levelOn+1,listOfX)
recLoop([3,2],0,[])
print sol
However it works as expected when I use pop() instead like this:
sol = []
def recLoop(levelWidth,levelOn,listOfX):
if len(listOfX) == 3:
sol.append([listOfX[0],listOfX[1]])
sol.append([listOfX[0],listOfX[2]])
listOfX.pop()
listOfX.pop()
listOfX.pop()
print listOfX
if len(levelWidth) != levelOn:
for x in range(levelWidth[levelOn]):
listOfX.append(x)
recLoop(levelWidth,levelOn+1,listOfX)
recLoop([3,2],0,[])
print sol
NOTE: the outcome of the first code is:
[[0, 0], [0, 1]]
but it should be:
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
The statement:
listOfX = []
simply rebinds the local variable (which is just a reference to an object) to a new list. The original list object is still referenced elsewhere but not affected by this rebinding. Using listOfX.pop() on the other hand directly manipulates that object.
You can use:
listOfX[:] = []
to clear the list, instead.
Related
I have two lists: a = [0], b = [[0,1]], I want to append 2 to a first, then append a to b. So b should be [[0,1], [0,2]].
Operations like this work well:
a.append(2)
b.append(a)
but when I tried to combine them:
b.append(a.append(2))
I got the results:
a = [0, 2], b = [[0, 1], None]
What's wrong here?
As answered in the comments, a.append(2) only appends 2 to the list a, but it doesn't actually return it. An append operation that doesn't modify the original list but returns a new list with the appended value can be written simply with the +-operator.
>>> a, b = [0], [[0, 1]]
>>> b.append(a + [2]) # The list that is returned to the append function is [0, 2]
>>> a
[0]
>>> b
[[0, 1], [0, 2]]
I think the comments already answered your question: the append() method modifies the list in place instead of creating a new one, and its return type is None. If you still want to do the operation in a single line, you could use an assignment expression:
a, b = [0], [[0, 1]]
b.append(a := a + [2])
print(a, b)
# [0, 2] [[0, 1], [0, 2]]
If you want to combine those you might make your own function,
def append_ret(x, value):
x.append(value)
return x
doing the operation and returning the 'appended' container.
append_ret(b, append_ret(a,1))
I have a nested list, and I need to reverse every element in the list.
Below is the example :
L = [[0, 1, 2], [1, 2, 3]]
Expected Output :
L = [[3, 2, 1], [2, 1, 0]]
I tried with the below piece of code, it works individually but when I am putting this code within function, then the list is not getting updated.
L = [list(reversed(row)) for row in L]
L.reverse()
This code works, and the List "L" is getting updated.
But when I put this code in function
def deep_rev(L):
L = [list(reversed(row)) for row in L]
L.reverse()
L = [[0, 1, 2], [1, 2, 3]]
deep_rev(L)
print(L)
This is returning the same list = [[0,1,2],[1,2,3]]
Can anyone please help me in this regard, why in function this is not working?
With L = ... you are assigning a new value to the parameter L within the function, without modifying the original list. Instead, you can use L[:] = ... to replace all the elements in the original list with the values from the new list.
def deep_rev(L):
L[:] = [list(reversed(row)) for row in reversed(L)]
L = [[0, 1, 2], [1, 2, 3]]
deep_rev(L)
print(L) # [[3, 2, 1], [2, 1, 0]]
Your current code creates a new list, rather than modifying the exiting list in place. You can make it work, just get rid of the list comprehension and do in-place reversals for the inner lists too:
def deep_rev(L):
for inner in L:
inner.reverse()
L.reverse()
If you want to support more than two levels of nesting, you could recursively call deep_rev on the inner lists, rather than just reversing them as I did above. You'd need to check if the values were lists or not, so you'd have a base case.
This is the solution I find out using recursion:
l=[[0, 1, 2], [1, 2, 3]]
def treereverse(l):
l.reverse()
for x in l:
if isinstance(x,list):
treereverse(x)
return l
print(treereverse(l))
This Code works for your problem,
L = [[0, 1, 2], [1, 2, 3]]
b=list(reversed(L))
q=[]
for i in b:
q.append(list(reversed(i)))
print q
Output:-
[[3, 2, 1], [2, 1, 0]]
def deep_rev(l):
l = [list(reversed(row)) for row in l]
l.reverse()
return l
l = [[0, 1, 2], [1, 2, 3]]
l = deep_rev(l)
print(l)
output
[[3, 2, 1], [2, 1, 0]]
deep_rev(L) modifies one local list, its scope is inside this function. Either make one deep copy of the list or return the reversed list.
I have a python code where I want to open N files, and for each file, get 3 separate lists for particulars in X and Y (the last one for weight).
I managed to read a file, and to store it in different lists which are stored in a "main" list which stores lists.
But when my code reads the second file, I did the same as the first with the same name of list. But when I print the main list, it shows me L2 L2 for example, instead of L1 L2
I know this is because I use the same list, x1 for the 2 files and so the variable just change in final list, but as of right now, I have no clue on how to get something working right.
Here's the code
import os
x1 = []
y1 = []
p1 = []
Xtotal = []
Ytotal = []
listcount = 0
def stockage(z):
compteur = 0
del x1[:]
del y1[:]
del p1[:]
for ligne in z :
if ligne[0:1]=='#':
pass
else:
if ligne[0:1]=='p':
p1.append(float(ligne[2:]))
else:
compteur = compteur + 1
if compteur%2 == 0 :
y1.append(float(ligne.rstrip()))
else:
x1.append(float(ligne.rstrip()))
Xtotal.append(x1)
Ytotal.append(y1)
print(Xtotal)
for fichier in os.listdir('data/'):
fichierOuvert = open("data/"+fichier, "r")
listetotale=stockage(fichierOuvert)
fichierOuvert.close()
print(Xtotal)
print(x1)
print(y1)
print(p1)
And here's a sample file which is used as an imput :
'#'This file contains points particulars and the line with p= its weight
'#'PointA :
p=20
12
22
'#PointB :'
34
26
'#PointC :'
28
98
'#PointD :'
97
54
The result you're getting for Xtotal currently looks something like this:
[x1, x1]
because you're adding the same list twice. So, when you make changes to x1, you make changes to every list in Xtotal. Using del doesn't change that. Instead, you want to create entirely new lists each time your function is called.
What you need to do is move the definitions of your lists (x1 = [], etc.) into your function (where you currently have del x1[:]), and get rid of the lines where you clear out those lists (remove del x1[:], del y1[:], etc.). You will then have to remove the lines printing x1, y1, and p1 from the end of your script, but you can accomplish the same thing by doing
print(Xtotal[-1])
print(Ytotal[-1])
instead.
If you also add a variable Ptotal in the same way you have Xtotal and Ytotal, then you will have access to p1 as well, in the same way.
Perhaps this example will demonstrate what is going on:
x1 = []
Xtotal = []
def make_some_data(length):
del x1[:]
x1.extend(range(length))
Xtotal.append(x1)
print(Xtotal)
for i in range(1,5):
make_some_data(i)
print(Xtotal)
#output
[]
[[0]]
[[0, 1], [0, 1]]
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> [id(item) for item in Xtotal]
[4386547144, 4386547144, 4386547144, 4386547144]
>>> [id(item)==id(x1) for item in Xtotal]
[True, True, True, True]
When you erase the content of the list x1 you also get rid of the data you previously generated, rendering any reference to it instead point to the new data you fill it up with, instead you need to use local variables to make new lists as you need them:
Xtotal = []
def make_some_data(length):
x1 = []
x1.extend(range(length))
Xtotal.append(x1)
print(Xtotal)
for i in range(1,5):
make_some_data(i)
print(Xtotal)
#output:
[]
[[0]]
[[0], [0, 1]]
[[0], [0, 1], [0, 1, 2]]
[[0], [0, 1], [0, 1, 2], [0, 1, 2, 3]]
I'm having problems with my lists.
Obviously, I have just missed something. :P
Can someone tell me what is going wrong here and how to fix it?
Here is where I am having the malfunction:
On = [0, 0, [[0, 0],[0,1]]]
tempList = []
tempList.append(On[2])
print(tempList)
tempList.append([On[0],On[1]+1])
print(tempList)
Just in case this is important, it is for my AI pathfinding.
The First Print:
[[[[0, 0]], [0, 1]]]
I wanted:
[[0,0],[0,1]]
The Second Print:
[[[[0, 0]], [0, 1]], [0, 2]]
I wanted:
[[0,0],[0,1],[0,2]]
On[2] is supposed to track my past movements.
I was trying to get my past movements (On[2]) to combine with the current movement.
I want the tempList to be like this:
[[0,1],[0,2],[0,3]]
But instead I get this:
[[[0,1],[0,2]],[0,3]]
On is stored in this format(Or supposed to be): [CurrentX,CurrentY,[[Step1X,Step1Y],[Step2X,Step2Y]] etc.
If you need any more info, just tell me what you need.
EDIT: The problem is whith the On and the tempList.
EDIT2: If you people need to, I can post all of the code so you can run it. :/
This line:
tempList.append([On[0],On[1]+1])
appends a list to the list. You want this:
tempList.extend([On[0], On[1] + 1])
On = [0, 1, [[0, 0],[0,1]]]
tempList = []
tempList.extend(On[2])
print(tempList)
tempList.append([On[0],On[1]+1]) # changing only this line
print(tempList)
...yields...
[[0, 0], [0, 1]]
[[0, 0], [0, 1], [0, 2]]
...which is the stated desired result.
If your Bottom comes out as...
[0, 0, [[[0,1],[0,2],[0,3]]]]
...when you want it to be...
[0, 0, [[0,1],[0,2],[0,3]]]
...then the problem may not be with tempList and its construction at all, but with the append call, which appends its argument as a single element.
That is to say:
a=[1,2]
b=[3]
a.append(b)
...results in...
a == [1,2,[3]]
...rather than...
a == [1,2,3]
...which I'm presuming is what you actually want.
For that result, use either
a += b
or
a.extend(b)
I'm trying to create a function that returns all the circular numbers from a given number, and it's giving me an odd result. The function is:
def getcircs(mylist):
circs=[]
x=mylist
y=list(x)
dig=len(x)-1
j=0
circs.append(x)
while j < dig:
for i in range(0,dig):
r=i+1
g=x[r]
y[i]=g
y[dig]=x[0]
print y
circs.append(y)
x=list(y)
j+=1
print circs
return circs
And as you can see when you run it, the lists 'y' are returning what I'm looking for, but the list 'circs' doesn't seem to have the right 'y' value appending to it. I'm wondering if it's an issue with the way Python references lists, but I can't figure it out. Thanks.
This is because lists are by reference and you re-use y. When you append y to circs, circs gets another reference to y. When you later modify y, you will see the change in each spot in circs where y was appended. Try making a copy of y and working with that.
def getcircs(mylist):
circs=[]
x=mylist
y=list(x)
dig=len(x)-1
j=0
circs.append(x)
while j < dig:
temp = y[:]
for i in range(0,dig):
r=i+1
g=x[r]
temp[i]=g
temp[dig]=x[0]
print temp
circs.append(temp)
x=list(temp)
j+=1
print circs
return circs
The line temp = y[:] just creates temp as a full slice of y, which natively produces a copy.
In case you want to do it a simpler way (in my opinion anyway) you might benefit from using itertools.cycle here. This approach could be cleaned up too, but you get the idea:
import itertools
my_list = [1, 2, 3, 4]
cycler = itertools.cycle(my_list)
list_size = len(my_list)
for i in range(list_size):
print [cycler.next() for j in range(list_size)] # call next on the cycler generator
cycler.next() # skip the next number
OUTPUT
[1, 2, 3, 4]
[2, 3, 4, 1]
[3, 4, 1, 2]
[4, 1, 2, 3]
In fact, here is a one-liner for it:
print [[cycler.next() for j in range(list_size + 1)][:-1] for i in range(list_size)]
OUTOUT
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]