I'm creating a group sorting function for my first major project - a schedule maker for my partner's lesson groups at her job (teacher). There are 20 letters. 4 letters can go per day, so all 20 letters should go every 5 days. I created 5 smaller groups (lists) of 4 letters nested inside a list titled "all_groups". Every 5 days (a week or so) the order of the groups is rotated by one by insert(0, group.pop()). This works without a problem. However, I also want to rotate the 5 nested lists themselves and have that persist. This is the part that isn't working.
I have a couple helper global counters to make this work.
I add 1 to each counter every time the function is called. Counter 1 - randomizer. If randomizer == 21, then rotate the 5 main groups.
Counter 2 - Total changes. This counts the total amount of times the function has been called. I use this to avoid rotating any nested lists the first go-around using a conditional.
Counter 3 - group_index - this counter goes from 0-4 and lets the function choose which of the 5 groups should be called before resetting back to 0.
Counter 4 - group_changes. This counter goes counts from 0-3 since there are 4 letters in each list. Once all 4 letters have been rotated, it should reset to 0 if group_changes == 4, and increase the group_index by 1.
The rotating of the 5 subgroups in the main list and changing of index seems to work, and each individual letter is rotated once and prints correctly, but any further loops tends to reset the inner lists back to their original state rather than keeping them modified. I'm stumped as to how to fix this.
In addition: If I use the randomize_group function rather than the rotate_group function every time all 20 letters have gone if group_ranzomier == 21), the nested lists SOMETIMES rotate inside. I would like to randomize rather than rotate the 5 lists for scheduling purposes. I have no clue why randomizing the 5 lists changes the behavior of the inner rotating function.
The code I have for this portion of the project is as follows, and I commented on the code to describe what it's doing temporarily:
group_randomizer = 0 #this is for randomizing the subgroup order each loop of 20 groups
group_change = 0 #tracks individual swaps
group_index = 0 #tracks each subgroup of 5 groups of 4
total_changes = 0 #tracks total group swaps
all_groups = [['A', 'B', 'C', 'D'],
['E', 'F', 'G', 'H'],
['I', 'J', 'K', 'L'],
['M', 'N', 'O', 'P'],
['Q', 'R', 'S', 'T']]
def main():
#this entire block of code is for testing purposes to see what the output is
print(all_groups[group_index])
for i in range(20):
print(find_group(all_groups), end='')
print("")
print(tabulate(all_groups))
for i in range(8):
for i in range(20):
print(find_group(all_groups), end='') #printing the entire 20 group loop in one line
print(all_groups[group_index]) #to see what the first line is
print(tabulate(all_groups)) #for testing purposes, to read table
print("")
def rotate_group(group):
group.insert(0, group.pop())
return group
# def randomize_group(group):
# random.shuffle(group)
# return group
def find_group(all_groups):
global group_randomizer
global group_change
global group_index
global total_changes
group_randomizer = 1
if group_randomizer == 21:
rotate_group(all_groups) #rotates the 5 subgroups of 4 after each letter has gone through
group_randomizer = 0
if total_changes < 19: #to keep groups un-randomized the first loop of 20 groups. base case
rotated = all_groups[group_index][group_change]
else: #begin rotating the letters in the subgroups. ABCD -> DABC -> CDAB -> BCDA -> ABCD
all_groups = rotate_group(all_groups[group_index])
rotated = all_groups
total_changes = 1 #increment total changes
group_change = 1 #increment a rotation counter.
if group_change == 4: #if the rotation counter reaches 4, reset it and increment the subgroup index
group_index = 1
group_change = 0
if group_index == 5: #if the subgroup index reaches 5, reset it to return back to the first subgroup
group_index = 0
return rotated[0] #return the current rotated letter
CodePudding user response:
Your code actually does work, it just needed one change. I'm not sure how you are calling this so I just called it 21 times in a loop. The only changes I made are in the else
clause. You were assigning an all_groups
sub-list to all_groups
. I just added the appropriate index. You were assigning all of all_groups
to rotated
. I just added the appropriate index.
Considering you didn't mention an error, and you claim your code isn't working, I'm going to assume you call this function one time, but your code doesn't change all_groups
til the 20th time. If you would have hit the 20th time you would have gotten an error stating that string values don't have an insert method.
group_randomizer = 0 #this is for randomizing the subgroup order each loop of 20 groups
group_change = 0 #tracks individual swaps
group_index = 0 #tracks each subgroup of 5 groups of 4
total_changes = 0 #tracks total group swaps
all_groups = [['A', 'B', 'C', 'D'],
['E', 'F', 'G', 'H'],
['I', 'J', 'K', 'L'],
['M', 'N', 'O', 'P'],
['Q', 'R', 'S', 'T']]
def rotate_group(group):
group.insert(0, group.pop())
return group
def find_group(all_groups):
global group_randomizer
global group_change
global group_index
global total_changes
group_randomizer = 1
if group_randomizer == 21:
rotate_group(all_groups) #rotates the 5 subgroups of 4 after each letter has gone through
group_randomizer = 0
if total_changes < 19: #to keep groups un-randomized the first loop of 20 groups. base case
rotated = all_groups[group_index][group_change]
else: #begin rotating the letters in the subgroups. ABCD -> DABC -> CDAB -> BCDA -> ABCD
#was all_groups = rotate_group(all_groups[group_index])
all_groups[group_index] = rotate_group(all_groups[group_index])
#was rotated = all_groups
rotated = all_groups[group_index]
total_changes = 1 #increment total changes
group_change = 1 #increment a rotation counter.
if group_change == 4: #if the rotation counter reaches 4, reset it and increment the subgroup index
group_index = 1
group_change = 0
if group_index == 5: #if the subgroup index reaches 5, reset it to return back to the first subgroup
group_index = 0
return rotated[0] #return the current rotated letter
#this is how I called the script
#you didn't provide your method
for i in range(21):
find_group(all_groups)
print(all_groups)
CodePudding user response:
I'm positive that it would be better to change the approach to the problem in order to derive a clearer solution. E.g., I'd recommend to think of a class for "all_groups" and "group" entities with a relevant rotation method for the objects. Anyway, if we keep the code logic as it is I've spotted 2 errors:
- A subgroup is assigned to the all_groups
# all_groups = rotate_group(all_groups[group_index])
all_groups[group_index] = rotate_group(all_groups[group_index])
- For total_changes < 19 the variable "rotated" is assigned a letter of str type and further it's assigned a subgroup of list type
It can be fixed in the return line.
# return rotated[0]
return rotated[0] if type(rotated) == list else rotated #return the current rotated letter
Edit: Also, I think if the code is meant to get all the 20 subsequent letters for the first 20 times than compare total_changes to 20 instead of 19
if total_changes < 20: #to keep groups un-randomized the first loop of 20 groups. base case
rotated = all_groups[group_index][group_change]