The problem: I have a list of tuples containing a string and an int. I have managed sorting the tuples by their second value using the built in sorted function and lambda. The problem with that is that I also need to group up the tuples in case they have the same int. After they are sorted in groups I need to generate a random number between 1 and 6 and based on the highest put the corresponding tuple inside a final list which is meant to represent the truly sorted tuples.
Context: The algorithm is meant to be an Initiative roller for a roleplay game and comparing one value to the next does not suffice, all tuples that have the same int value need to be compared at the same time and not one after another.
Current code:
iniList = [('Enemy 3', 15), ('Aldare', 14), ('Enemy 2', 14), ('Enemy 5', 14), ('Enemy 1', 13), ('Enemy 4', 13)]
finalIniList = [] #the list meant to contain the tuples when they are sorted
iniGroups = []
currentIni = iniList[0][1]
currentIniGroup = []
finalIniList = []
for x in range(len(iniList)):
if(currentIni == iniList[x][1]):
currentIniGroup.append(iniList[x])
if(x == len(iniList) - 1): iniGroups.append(currentIniGroup)
else:
iniGroups.append(currentIniGroup)
currentIniGroup = []
currentIniGroup.append(iniList[x])
currentIni = iniList[x][1]
if(x == len(iniList) - 1): iniGroups.append(currentIniGroup)
for item in iniGroups:
print(item)
Output:
[('Enemy 3', 15)]
[('Aldare', 14), ('Enemy 2', 14), ('Enemy 5', 14)]
[('Enemy 1', 13), ('Enemy 4', 13)]
CodePudding user response:
Given
iniList = [('Enemy 3', 15), ('Aldare', 14), ('Enemy 2', 14), ('Enemy 5', 14), ('Enemy 1', 13), ('Enemy 4', 13)]
use itertools.groupby
and random.sample
:
from random import sample
from itertools import groupby
finalIniList = [(group[0],
sample(list_:=[tup[0] for tup in group[1]],k=len(list_)),
)
for group in groupby(iniList,key=lambda tup: tup[1])
]
to get something like
>>> finalIniList
[
(highest_initiative, ['shuffled', 'list', 'of', 'entities']),
(lower_initiative, ['entity']),
(lowest_initiative, ['some', 'more', 'entities', 'randomly', 'ordered']),
]
CodePudding user response:
After they are sorted in groups I need to generate a random number between 1 and 6 and based on the highest put the corresponding tuple inside a final list which is meant to represent the truly sorted tuples.
And how do you break ties if that randomly generated number is the same for two items?
If you're satisfied with simply randomly uniformly sorting within the groups, you could do the following:
import random
def sort_with_grouping(ll):
n = len(ll)
idx_list = list(range(n))
random.shuffle(idx_list)
ll_with_idx = [(s, i, i*n idx)for (s, i), idx in zip(ll, idx_list)]
ll_with_idx.sort(key=lambda t: -t[2])
return [(s, i) for (s, i, _) in ll_with_idx]
This works provided the square of the length of your list if smaller than the maximum integer, which I doubt will be a problem. You can seed the random number generator if you wish.