Related
This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 1 year ago.
I am trying to do a simple task in python and I cannot figure out why it is failing at the append() function.
d = pd.DataFrame([1,2,3,4,5,6,1,2,3,])
d.columns = ['prediction_num']
def cumulative_vector(df):
vector = [0,0,0,0,0,0,0,0,0]
vectorL = []
for i in df.prediction_num.values:
vector[i] += 1
print(vector)
vectorL.append(vector)
df['cumulative_histogram'] = vectorL
print(df.cumulative_histogram)
return df
cumulative_vector(d)
When I print out the vector variable in the loop, I get the right output, which is:
[0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 0, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 0, 0, 0]
[0, 1, 1, 1, 1, 1, 1, 0, 0]
[0, 2, 1, 1, 1, 1, 1, 0, 0]
[0, 2, 2, 1, 1, 1, 1, 0, 0]
[0, 2, 2, 2, 1, 1, 1, 0, 0]
However, when I print the newly created df.cumulative_histogram column, I get this:
0 [0, 2, 2, 2, 1, 1, 1, 0, 0]
1 [0, 2, 2, 2, 1, 1, 1, 0, 0]
2 [0, 2, 2, 2, 1, 1, 1, 0, 0]
3 [0, 2, 2, 2, 1, 1, 1, 0, 0]
4 [0, 2, 2, 2, 1, 1, 1, 0, 0]
5 [0, 2, 2, 2, 1, 1, 1, 0, 0]
6 [0, 2, 2, 2, 1, 1, 1, 0, 0]
7 [0, 2, 2, 2, 1, 1, 1, 0, 0]
8 [0, 2, 2, 2, 1, 1, 1, 0, 0]
Why does the column only contain the last value of vector in the loop and not each iterative value? It is appended during each loop, so I am unsure what I am missing.
For loop is reusing your old vector object. This means that at each iteration you only have one list that you are modifying. Printing is working fine because you are printing the state of the list at a specific point in time.
r = []
for idx in range(0,10):
r.append(idx)
print(r)
---
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for idx in range(0,10):
r = []
r.append(idx)
print(r)
---
[9]
To fix your specific case, add [:] to append a copy of the list instead.
# ...
for i in df.prediction_num.values:
vector[i] += 1
print(vector)
vectorL.append(vector[:]) # vector -> vector[:] here
I have a (long) list in which zeros and ones appear at random:
list1 = [1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
1.I want to get another list
the sum of the list up to where 0 appears
where 0 appears, retain 0 in the list
list2 = [3, 0, 2, 0, 1, 0, 3]
It should work for corner cases as well like zeroes at start or end
list1 = [0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0]
list2 = [0, 3, 0, 2, 0, 1, 0, 3, 0]
You can use itertools.groupby:
from itertools import groupby
list1 = [1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
out = []
for v, g in groupby(list1):
if v:
out.append(sum(g))
else:
out.extend(g) # or out.append(0) if you want to keep only single zero
print(out)
Prints:
[3, 0, 2, 0, 1, 0, 3]
For list1 = [0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0] it prints:
[0, 3, 0, 2, 0, 1, 0, 3, 0]
If you want to do it the plain-vanilla way without importing anything, you could do:
list2 = [1] if list1[0] else [0] # Initialise
for i in range(1, len(list1)):
if list1[i] and list1[i-1]:
list2[-1] += 1
elif list1[i]:
list2.append(1)
elif list1[i-1]:
list2.append(0)
For
[1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
[0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1]
[1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0]
this gives:
[3, 0, 2, 0, 1, 0, 3]
[0, 3, 0, 2, 0, 1, 0, 3]
[3, 0, 2, 0, 1, 0, 3, 0]
respectively.
I have a list of lists(called table):
table = [[0, 1, 2], [1, 2, 1], [2, 3, 2], [0, 2, 3], [0, 3, 2], [1, 3, 3]]
where the first element of each sub list is the start point, the second is the endpoint and the third is the distance between the two points. So e.g. [0,1,2] means the gap between the point 0 and 1 is 2.
Now I want to use the information in table, to construct another list of lists(called distances) containing all the distances between all the points. So that, I could for example, call distances[0][2] (meaning I want the distance between point 0 and point 2, so the output should be 3).
However I am having trouble correctly separating the date from table and putting it into distances.
My code so far is this:
dstFromOnePoint = []
distances = []
numberOfPoints = 4 #0,1,2,3
for i in range(numberOfPoints): #loops through all start points
for j in range(numberOfPoints): # loops through all endpoints
for val in table:
if (val[0] == i and val[1] == j) or (val[0] == j and val[1] == i): # checks start node , end node
dst = val[2]
dstFromOnePoint.append(dst)
elif (i==j): #distance from one point to itself will be 0
dstFromOnePoint.append(0)
distances.append(dstFromOnePoint)
print(distances)
print(distances[0][2])
The output I get:
[[0, 0, 0, 0, 0, 0, 2, 3, 2, 2, 0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2, 3, 2, 2, 0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2, 3, 2, 2, 0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 2, 3, 2, 2, 0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 2, 2, 3, 2, 0, 0, 0, 0, 0, 0]]
0
The output I should get:
[[0,2,3,2], [2,0,1,3], [3,1,0,2], [2,3,2,0]]
3
I think I'm using my loops incorrectly because I end up appending the same list multiple times, but even just looking at one individual sub list, I don't have the correct values, so I probably have more issues that I don't know how to fix?
Here is a correct and more compact solution:
numberOfPoints = 4
distances = [numberOfPoints * [0] for _ in range(numberOfPoints)]
for x, y, d in table:
distances[x][y] = d
distances[y][x] = d
You need to pre-populate the distance matrix and then assign per [i][j]
Fixes on your original solutions:
table = [[0, 1, 2], [1, 2, 1], [2, 3, 2], [0, 2, 3], [0, 3, 2], [1, 3, 3]]
distances = []
numberOfPoints = 4 #0,1,2,3
distances = [[0 for _ in range(numberOfPoints)] for _ in range(numberOfPoints)]
for i in range(numberOfPoints): #loops through all start points
for j in range(numberOfPoints): # loops through all endpoints
for val in table:
if (val[0] == i and val[1] == j) or (val[0] == j and val[1] == i): # checks start node , end node
dst = val[2]
distances[i][j] = dst
# actually you can drop this elif as distances is intitalized to 0
elif (i==j): #distance from one point to itself will be 0
# dstFromOnePoint.append(0)
distances[i][j] = 0
# distances.append(dstFromOnePoint)
print(distances)
print(distances[0][2])
gives:
[[0, 2, 3, 2], [2, 0, 1, 3], [3, 1, 0, 2], [2, 3, 2, 0]]
3
here is one line using itertools.groupby:
from itertools import groupby
[[next(g)[2] if j!=i else 0 for j in range(len(table[0]) + 1 )] for i, (k, g) in enumerate(groupby(sorted(e for f, s, t in table for e in [[f, s, t], [s, f, t]]), key=lambda x: x[0]))]
output:
[[0, 2, 3, 2], [2, 0, 1, 3], [3, 1, 0, 2], [2, 3, 2, 0]]
I made a similar post here. Now I am trying to generalize what was done there for an entire matrix of numbers.
Specifically I want to do this:
dates = []
dates.append(NDD_month[0])
for i in range(1,len(cpi)):
dates.append((dates[i-1] + 12 - number_of_payments[:i]) % 12)
print(dates)
where the number_of_payments is a matrix of type <class 'list'>.
Here is an example:
print(number_of_payments[:1])
is
[array([[0, 1, 0, 1, 1, 1, 0, 5, 1, 0, 2, 1]])]
After performing what I want then
print(dates[:1])
Should be
[array([[8, 8, 7, 7, 6, 5, 4, 4, 11, 10, 10, 8]])]
or something like that.
EDIT:
Here is an example of what my data looks like:
print(number_of_payments[:3])
This gives me this:
[
array(
[
[0, 1, 0, 1, 1, 1, 0, 5, 1, 0, 2, 1]
]),
array(
[
[0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0],
[1, 3, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0]
]),
array(
[
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 2, 0, 2, 1, 1, 0, 2, 1, 0, 0]
])
]
print(NDD_month[:3])
Gives me
[8, 7, 11]
Now for the answer I want I want to do something like this that I did in my earlier post where I had
dates = []
dates.append(NDD_month[0])
for i in range(1, len(first_payments)):
dates.append((dates[i-1] + 12 - first_payments[i-1]) % 12)
print(dates)
This gave me the correct output of
[8 8 7 7 6 5 4 4 11 10 10 8]
But now since I have the number_of_payments being a matrix I need to apply the same logic to this larger data structure. Let me know if that is clear.
Edit 2:
Okay this is hard to explain so I am going to go step by step example, I have this data or matrix (number_of_payments) whatever it is in python:
[[0, 1, 0, 1, 1, 1, 0, 5, 1, 0, 2, 1],
[0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0],
[1, 3, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0]]
I have another list or vector called NDD_month, the first three elements are
[8, 7, 11]
Now for sake of simplicity lets say I just have the first row of number_of_payments i.e.
[0, 1, 0, 1, 1, 1, 0, 5, 1, 0, 2, 1]
Further for simplicity lets say I have just the first element of NDD_month so
8
Then to get the answer I seek I would do this that Aurora Wang provided a nice answer too which was this
first_payments = number_of_payments[:1]
first_payments = first_payments[0][0]
dates = []
dates.append(NDD_month[0])
for i in range(1, len(first_payments)):
dates.append((dates[i-1] + 12 - first_payments[i-1]) % 12)
print(dates)
This gives me [8, 8, 7, 7, 6, 5, 4, 4, 11, 10, 10, 8].
Now I need to do the same thing but for each row in the matrix and each element in the NDD_month vector. I hope that makes it much more clear.
I was thinking this may work but again I am new to python and this does not work:
dates = []
for i in range(1,len(NDD_month)):
dates.append(NDD_month[i-1])
for j in range(1, len(NDD_month)):
dates.append((dates[j-1] + 12 - number_of_payments[i-1][j-1]) % 12)
print(dates)
If I understood you right, you want to do something like this:
number_of_payments = [
[0, 1, 0, 1, 1, 1, 0, 5, 1, 0, 2, 1],
[0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0],
[1, 3, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0]
]
NDD_month = [8, 7, 11]
dates = []
for i in range(len(number_of_payments)):
dates.append([NDD_month[i]])
for j in range(1, len(number_of_payments[i])):
dates[i].append((dates[i][j-1] + 12 - number_of_payments[i][j-1]) % 12)
print(dates)
I have basically a 2d grid array that is created with this:
def createRoom(self):
self.room = [[0] * 8 for x in xrange(8)]
for x in xrange(8):
self.room[x][0] = 2
for j in xrange(8):
self.room[0][j] = 2
for i in xrange(8):
self.room[-1][x] = 2
for n in xrange(8):
self.room[n][-1] = 2
for x in xrange(6):
self.room[1][x+1] = 1
for x in xrange(1):
self.room[2][x+6] = 1
for x in xrange(1):
self.room[3][x+6] = 2
for x in xrange(1):
self.room[4][x+6] = 2
for x in xrange(1):
self.room[3][x+5] = 1
for x in xrange(1):
self.room[4][x+5] = 1
for x in xrange(1):
self.room[5][x+6] = 1
for x in xrange(6):
self.room[6][x+1] = 1
for x in xrange(5):
self.room[x+1][1] = 1
return self.room
and using PrettyPrinter it looks like this:
[ [2, 2, 2, 2, 2, 2, 2, 2],
[2, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 0, 0, 0, 0, 1, 2],
[2, 1, 0, 0, 0, 1, 2, 2],
[2, 1, 0, 0, 0, 1, 2, 2],
[2, 1, 0, 0, 0, 0, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 2],
[2, 2, 2, 2, 2, 2, 2, 2]]
but when I want to get self.room[6][3] it returns 1 instead of 2.
Unless I change the order to self.room[3][6], why is it doing this?
This is your "room". The way you've set it up, it will be 0-based indexing in row-major order.
[[2, 2, 2, 2, 2, 2, 2, 2],
[2, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 0, 0, 0, 0, 1, 2],
[2, 1, 0, 0, 0, 1, 2, 2], # <-- 4th row
[2, 1, 0, 0, 0, 1, 2, 2],
[2, 1, 0, 0, 0, 0, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 2], # <-- 7th row
[2, 2, 2, 2, 2, 2, 2, 2]]
room[6][3] is the 4th element in the 7th row, i.e. 1.
room[3][6] is the 7th element in the 4th row, i.e. 2.
Hope this clears things up.
I just want to point out how much easier it is to type
[[2, 2, 2, 2, 2, 2, 2, 2],
[2, 1, 1, 1, 1, 1, 1, 2],
[2, 1, 0, 0, 0, 0, 1, 2],
[2, 1, 0, 0, 0, 1, 2, 2],
[2, 1, 0, 0, 0, 1, 2, 2],
[2, 1, 0, 0, 0, 0, 1, 2],
[2, 1, 1, 1, 1, 1, 1, 2],
[2, 2, 2, 2, 2, 2, 2, 2]]
Than to type what you typed. But that aside, observe the following output, and perhaps you will understand.
>>> room[0]
[2, 2, 2, 2, 2, 2, 2, 2]
>>> room[1]
[2, 1, 1, 1, 1, 1, 1, 2]
>>> room[2]
[2, 1, 0, 0, 0, 0, 1, 2]
>>> room[3]
[2, 1, 0, 0, 0, 1, 2, 2]
>>> room[4]
[2, 1, 0, 0, 0, 1, 2, 2]
>>> room[5]
[2, 1, 0, 0, 0, 0, 1, 2]
>>> room[6]
[2, 1, 1, 1, 1, 1, 1, 2]
>>> room[7]
[2, 2, 2, 2, 2, 2, 2, 2]
>>> room[6][0]
2
>>> room[6][1]
1
>>> room[6][2]
1
>>> room[6][3]
1
self.room[6][3] is 1 because that is what you set it to in the following loop:
for x in xrange(6):
self.room[6][x+1] = 1