Zonova
Zonova

Reputation: 235

How to sort a list by the value of its elements, with the value defined in a different list in Python

Lets say I have a game where the players are denoted by a unique number. Then, say I have a list with a bunch of randomly chosen players, called playerList. So, the list isn't ordered(this could represent a bunch of players signing up for some contest, for example). Then, I have a second list called playerLevel, where the i'th entry tells you the level the i'th player is on.

So, if playerLevel = ['X', 'Y', 'X', 'Z'], then players 1 and 3 are on level X, player 2 is on level Y, and player 4 is on level Z.

Using list comprehensions, how can I make a new list(lets call it samelevel) where the player numbers are sorted into sublists, based on the players being on the same level?

So, in this example, sameLevel = [[1,3],[2],[4]]

I'd like to do this in a way that looks elegant. Ideally, using a main loop that looks like "for element in playerLevel:" and so on. How can I do this? Thanks!

Upvotes: 3

Views: 88

Answers (4)

Tagc
Tagc

Reputation: 9076

Alternative implementation using itertools.groupby (wwii beat me to it). Funnily enough someone posted a question about this exact function just a few hours ago.

Code

import itertools

X = 5
Y = 10
Z = 15

PLAYER_LEVELS = [X, Y, X, Z]

def group_by_player_level(player_levels):
    def by_level(pair):
        return pair[1]

    sorted_levels = sorted(enumerate(player_levels), key=by_level)
    return [[i + 1 for (i, _) in g] for _, g in itertools.groupby(sorted_levels, key=by_level)]

if __name__ == '__main__':
    print(group_by_player_level(PLAYER_LEVELS))

Output

[[1, 3], [2], [4]]

Upvotes: 0

Jack Morrison
Jack Morrison

Reputation: 1663

It doesn't use a list-comprehension, per se, but this will do it:

from collections import defaultdict
playerLevel = ['X', 'Y', 'X', 'Z']
sameLevel = defaultdict(list)
for idx, level in enumerate(playerLevel):
    sameLevel[level].append(idx)
print(sameLevel.values())

This results in [[1], [0, 2], [3]].

Upvotes: 3

wwii
wwii

Reputation: 23753

Using itertools.groupby

import operator, itertools
players = random.choices('xyzdeftup', k=20)
level = operator.itemgetter(1)
player = operator.itemgetter(0)
players = sorted(enumerate(players), key = level)
groups = itertools.groupby(players, key = level)
#for level, group in groups:
#    print('{}:\n\t{}'.format(level, str(list(map(player, group)))))
result = [list(map(player, group)) for level, group in groups]

Upvotes: 0

evan.oman
evan.oman

Reputation: 5572

I would use a dictionary instead of nested lists:

In [1]: pLevels = ["X", "Y", "Z", "X"]

In [2]: from collections import defaultdict

In [3]: lvlPlayerMap = defaultdict(list)

In [4]: for (pID, lvl) in enumerate(pLevels): lvlPlayerMap[lvl].append(pID)

In [5]: lvlPlayerMap
Out[5]: defaultdict(list, {'X': [0, 3], 'Y': [1], 'Z': [2]})

Upvotes: 2

Related Questions