Iteration moves the cursor in PyMongo? - python

Not sure what's happening here or why, it seems as if when I iterate on a cursor it moves it, because I can't run a second loop from the same starting point. My example:
players = db.player.find({'parent_api__id' : 'stats', 'game__id':{'$in':games_list}, "played":"true"});
count = 0;
for c in players:
count = count + 1
for c in players:
game = db.game.find_one({'parent_api__id':'schedule', 'id':c['game__id']})
c['date'] = game['scheduled']
print c
In this one it never enters the second loop, if I put a print up top it never hits it, and it never does the print c at the bottom
Now if I comment out the loop with the count in it, so it looks like this:
players = db.player.find({'parent_api__id' : 'stats', 'game__id':{'$in':games_list}, "played":"true"});
#count = 0;
#for c in players:
# count = count + 1
for c in players:
game = db.game.find_one({'parent_api__id':'schedule', 'id':c['game__id']})
c['date'] = game['scheduled']
print c
then it enters the 2nd loop and iterates completely fine (printing out as it goes along)
Why is this? do I have to reset the cursor every time in between with another players = db.player.find({'parent_api__id' : 'stats', 'game__id':{'$in':games_list}, "played":"true"}); ? Seems like that can't be the way it was intended.
Thanks for any help you can provide!

Yes, a cursor (by definition) points to the next item (document in case of Mongo) once the current item is iterated over, the cursor itself provides an iterator function and internally maintains a pointer to the items that have been "consumed".
There are two approaches to solve the problem you are facing,
First is to use the cursor's rewind() method to set the cursor to its unevaluated original state
Second, clone the cursor using clone(), which will give you a second cursor that will be an exact clone of the first one, but will be a completely new instance. Use this if you need to maintain states of the two cursors throughout or at the end of evaluation.

Related

Changing one dictionary at two different events leads to KeyError in some cases (because of timing of key event + event due to dt)

Copy of the final question at the bottom:
"I have no idea how to solve this bug. One action is time dependent and the other one is player input dependent. Someone with an idea? Is there something in python working with mutable data which handles cases where one object gets changed at different times from different places?"
I code my own Tetris in Pygame. At the moment my goal is to rebuild the game mode "Survival" from here: https://jstris.jezevec10.com/?play=4
The player needs to survive as long as possible while every 1 second a new line with only 1 free spot will be added at the bottom and shifts the game field towards the top.
My problem is, there is a key.event where the player drops a piece and clears a row with that action and on the other hand there is time event where every one second a line is randomly added to the field. Both events change values in a dictionary. In general this code works but there is very small window of time where dependent on the actions the code throws an error.
Short explanation of my game:
There is a grid ( list of lists 10x20 ) where each element is a RGB color (0,0,0) starting everytime with black and will be filled with information (colors) of the current falling piece or the field at the bottom where pieces are locked. The grid will be drawn every frame. Pieces which are already placed are stored in a dictionary. The grid requests the dict for the locked pieces every time before drawing.
In this picture you see the original game. At that moment 6 lines already are added to the field.
Every line will be generated at the bottom of the field with the grey colour with one free random spot. Everytime a line will be generated the information is added in my "locked" dictionary ( key = (x,y) : value = (153,153,153) ) and a function changes the y value in every key by 1 to the top.
At the same time if the player clears a row (in this picture it would be the 6th row counting from the bottom) there is a function which deletes this cleared row in the "locked" dict and changes all y values which are greater than that line by 1 to the bottom.
Here are the two functions:
def clear_rows(grid, locked): # (0,0) is at the top left, x increases right, y increases down
i = len(grid) - 1 # last row
rows_cleared = 0
while i > -1:
row = grid[i]
if BLACK not in row: #which means the row is full and can be cleared
i_new = i + rows_cleared
for j in range(len(row)):
del locked[(j, i_new)]
rows_cleared += 1
for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
x_coord, y_coord = key
if y_coord < i_new:
new_key = (x_coord, y_coord + 1)
locked[new_key] = locked.pop(key)
i -= 1
else:
i -= 1
return rows_cleared
and
def survival_add_line(locked):
for key in sorted(list(locked)):
x, y = key
new_key = (x, y - 1)
locked[new_key] = locked.pop(key)
gap = random.randint(0,9)
for i in range(10):
if not i == gap:
locked[(i, 19)] = SURVIVAL_GRAY
This is the code in my mainloop:
if level_time / 1000 >= 1:
survival_add_line(locked)
level_time = 0
if change_piece:
for pos in tetrimino_position:
locked[(pos[0], pos[1])] = current_piece.color
current_piece = next_pieces[0]
next_pieces.pop(0)
next_pieces.append(new_tetromino())
change_piece = False
cleared_lines += clear_rows(grid, locked)
I noticed the bug can only happen at the very bottom of the field. If I understand it right it happens when the player drops a piece in that exact moment when survival_add_line() is already called but before if change_piece.
Survival_add_line() shifts every line one to the top, then the clear_row function wants to delete the last row (which is now the second last) and it can't find the key in the last row to delete --> KeyError.
I have no idea how to solve this bug. One action is time dependent and the other one is player input dependent.
Someone with an idea?
Is there something in python working with mutable data which handles cases where one object gets changed at different times from different places?
Instead of calling both statements with if, an if/elif block gets the job done! (change_piece can now be delayed by 1 frame, but that's not noticeable for the player)
Posted on behalf of the question asker

Python issue with replace statement?

I've been write this practice program for while now, the whole purpose of the code is to get user input and generate passwords, everything almost works, but the replace statements are driving me nuts. Maybe one of you smart programmers can help me, because I'm kinda new to this whole field of programming. The issue is that replace statement only seems to work with the first char in Strng, but not the others one. The other funcs blower the last run first and then the middle one runs.
def Manip(Strng):
#Strng = 'jayjay'
print (Strng.replace('j','h',1))
#Displays: 'hayjay'
print (Strng.replace('j','h',4))
#Displays: 'hayhay'
return
def Add_nums(Strng):
Size=len(str(Strng))
Total_per = str(Strng).count('%')
# Get The % Spots Position, So they only get replaced with numbers during permutation
currnt_Pos = 0
per = [] # % position per for percent
rGen = ''
for i in str(Strng):
if i == str('%'):
per.append(currnt_Pos)
currnt_Pos+=1
for num,pos in zip(str(self.ints),per):
rGen = Strng.replace(str(Strng[pos]),str(num),4);
return rGen
for pos in AlphaB: # DataBase Of The Positions Of Alphabets
for letter in self.alphas: #letters in The User Inputs
GenPass=(self.forms.replace(self.forms[pos],letter,int(pos)))
# Not Fully Formatted yet; you got something like Cat%%%, so you can use another function to change % to nums
# And use the permutations function to generate other passwrds and then
# continue to the rest of this for loop which will generate something like cat222 or cat333
Add_nums(GenPass) # The Function That will add numbers to the Cat%%%
print (rGen);exit()

Copy and paste Python functions in Emacs

I have a program that looks something like (this is a silly example to illustrate my point, what it does is not very important)
count = 0
def average(search_term):
average = 0
page = 0
current = download(search_term, page)
while current:
def add_up(downloaded):
results = downloaded.body.get_results()
count += len(results)
return sum(result.score for result in results)
total = average*count
total += add_up(current)
average = total/count
print('Average so far: {:2f}'.format(average))
page += 1
current = download(search_term, page)
If I have the cursor on any of the lines 8–11 and press a key combination I want Emacs to copy or kill the add_up function, and then I want to move the cursor to line 2 and press a key combination and paste the function there, with the correct level of indentation for the context it is pasted in.
Is this possible, and if so, how would I do that?
With python-mode.el py-kill-def and yank would do the job.
However, there are some restrictions. py-kill-def must be called from inside def in question. So needs to go upward from line 11 first.
Also indenting after insert poses some problems: as indent is syntax, sometimes Emacs can't know which indentation is wanted. In example below have an indent of 4 first and of 8 in add_up probably is not wanted - however it's legal code. After indenting first line in body of add_up, py-indent-and-forward should be convenient for the remaining.
def average(search_term):
average = 0
def add_up(downloaded):
results = downloaded.body.get_results()
count += len(results)
return sum(result.score for result in results)
page = 0
current = download(search_term, page)
while current:
total = average*count
total += add_up(current)
average = total/count
print('Average so far: {:2f}'.format(average))
page += 1
current = download(search_term, page)
For this type of thing I usually use expand-region, which I choose to bind to C-=.
Using your example I can select the add_up() function by pressing C-= once, kill the region normally (C-k), move to line 2, and yank as usual (C-y).
Depending on what else you have configured for Python you may have to clean up some whitespace, or it may get cleaned up for you. For example, aggressive-indent would be helpful.
One manual option would be to reindent the pasted code with something like C-x C-x M-\.
I've been using smart-shift (available in Melpa) for this sort of thing. global-smart-shift-mode to enable (beware, it binds keys). Select the block you want to move (I'd use expand-region like Chris), and the default keybind C-S-c <arrow> starts moving it. Once you're shifting, the arrows (without C-S-c) shift further. Horizontal shifts use the major mode's indent offset (python-indent-offset for python.el).

Separating lists in a list through iteration

First off, this is a homework assignment, but I've been working on it for a week now and haven't made much headway. My goal for this function is to take a list of lists (each list contains data about a football player) and separate the lists based off of the teams which the players belong to. I also want to add up each player's data so that I wind up with one list for each team with all the player's stats combined.
Here's the code I have so far. The problem I'm currently running into is that some teams are printed multiple times with different data each time. Otherwise it appears to be working correctly. Also, we have the limitation imposed on us that we are not allowed to use classes.
def TopRushingTeam2010(team_info_2010): #running into trouble calculating the rusher rating for each team, it also prints out the same team multiple times but with different stats. And just not getting the right numbers and order.
total_yards = 0
total_TD = 0
total_rush = 0
total_fum = 0
#works mostly, but is returning some teams twice, with different stats each time, which
#should not be happening. so... yeah maybe fix that?
for item in team_info_2010:
team = item[0]
total_yards = item[2]
total_TD = item[3]
total_rush = item[1]
total_fum = item[4]
new_team_info_2010.append([team, total_yards, total_TD, total_rush, total_fum])
for other_item in team_info_2010:
if other_item[0] == team:
new_team_info_2010.remove([team, total_yards, total_TD, total_rush, total_fum])
total_yards = total_yards + other_item[2]
total_TD = total_TD + other_item[3]
total_rush = total_rush + other_item[1]
total_fum = total_fum + other_item[4]
new_team_info_2010.append([team, total_yards, total_TD, total_rush, total_fum])
Any help or tips as to which direction I should head, or if I'm even headed in the right direction?
One possible problem is that you are removing from team_info_2010 while you are iterating through the list. Try deleting that line of code. I don't see a clear reason why you would want to delete from team_info_2010 and behavior is often undefined when you modify an object while iterating through it. More specifically, try deleting the following line of code:
team_info_2010.remove(item)

Bubble sort error with nested (high scores) list - python

For my software major work I have to create a program. In summary, the high scores list needs to be sorted before it can be written to file. To do this, I am using a bubble sort and I can't use the inbuilt sort function. The text file that the data is being read from is stored in a nested list. The text file looks like this:
NameOne
10
NameTwo
15
NameThree
9
This is the bubble sort code I have but does not work:
b_not_sorted = True
while b_not_sorted:
counter = 0
b_not_sorted = False
for counter in range(len(highest_scores) - 1):
if highest_scores[counter] < highest_scores[counter + 1]:
b_not_sorted = True
highest_scores[counter], highest_scores[counter+1] = highest_scores[counter+1], highest_scores[counter]
counter = counter + 1
I need the scores to be sorted from highest to lowest. Any help would be greatly appreciated and you will be credited appropriately in my program credits :). Thanks.
Here's a hint:
Check how many times your outer while loop is running. It should be running more than once, correct? What will always happen that causes the loop to exit, no matter what?
Try going through the code line by line and seeing what happens at every point.
The statement b_not_sorted = False at the end of the outer loop results in the outer loop exiting after executing only once. You need to move that statement to another part of your code. Try changing the name of b_not_sorted to I_still_need_to_go_through_the_list in your head:
Obviously in the first line:
while I_still_need_to_go_through_the_list:
it should be True, since you haven't gone over the list at all. You don't know if it's in order or not.
and after the line:
if highest_scores[counter] < highest_scores[counter + 1]:
Of course then we still need to make another pass, since we just made a change to the list and need to make sure no further changes are needed.
But what if no changes are made? I_still_need_to_go_through_the_list should be False then. Hmmm. If we put I_still_need_to_go_through_the_list = False right before the for loop, then it will be False unless we make changes to the list, which is exactly what we want.
You're doing b_not_sorted = False right after the first iteration, but it shouldn't be there! The algorithm just stops before it finishes the sorting.
You should instead do b_not_sorted = True only if highest_scores[counter] < highest_scores[counter + 1]
Also, the swapping code can look much nicer in Python. Instead of using temp_var just do this:
highest_scores[counter], highest_scores[counter+1] = highest_scores[counter+1], highest_scores[counter]
Python style guide suggests that you shoudn't write == True or == False in if statements. Do it like this:
while b_not_sorted:

Categories