Tengo una lista 2D que contiene los nombres de los jugadores de fútbol, la cantidad de veces que marcaron un gol y la cantidad de veces que intentaron un tiro a puerta, respectivamente.
player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]]
De esta lista, estoy tratando de devolver otra lista que muestra solo una instancia de cada jugador con sus respectivos goles totales e intentos totales de gol, así:
player_stats_totals = [['Adam', 30, 45], ['Kyle', 12, 18], ['Jo', 26, 49], ['Charlie', 31, 58]]
Después de buscar en Stack Overflow, pude aprender (deeste hilo ) cómo devolver los índices de los reproductores duplicados
x = [player_stats[i][0] for i in range (len(player_stats))] for i in range (len(x)): if (x[i] in x[:i]) or (x[i] in x[i+1:]): print (x[i], i)pero me quedé atascado sobre cómo proceder a partir de entonces y si, de hecho, este método es estrictamente relevante para lo que necesito (?)
¿Cuál es la forma más eficiente de devolver la lista deseada de totales?
Usa un diccionario para acumular los valores de un jugador determinado:
player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]] lookup = {} for player, first, second in player_stats: # if the player has not been seen add a new list with 0, 0 if player not in lookup: lookup[player] = [0, 0] # get the accumulated total so far first_total, second_total = lookup[player] # add the current values to the accumulated total, and update the values lookup[player] = [first_total + first, second_total + second] # create the output in the expected format res = [[player, first, second] for player, (first, second) in lookup.items()] print(res)Producción
[['Adam', 30, 45], ['Kyle', 12, 18], ['Jo', 26, 49], ['Charlie', 31, 58]] Una versión más avanzada y pitónica es usar un collections.defaultdict :
from collections import defaultdict player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]] lookup = defaultdict(lambda: [0, 0]) for player, first, second in player_stats: # get the accumulated total so far first_total, second_total = lookup[player] # add the current values to the accumulated total, and update the values lookup[player] = [first_total + first, second_total + second] # create the output in the expected format res = [[player, first, second] for player, (first, second) in lookup.items()] print(res)Este enfoque tiene la ventaja de omitir la inicialización. Ambos enfoques son O(n).
notas
La expresion:
res = [[player, first, second] for player, (first, second) in lookup.items()]es una lista por comprensión , equivalente al siguiente bucle for:
res = [] for player, (first, second) in lookup.items(): res.append([player, first, second])Además, lea esto para comprender el desembalaje.
Lo que quieres hacer es usar un diccionario donde la clave sea el nombre del jugador y el valor sea una lista que contenga [goles, tiros]. Construirlo se vería así:
all_games_stats = {} for stat in player_stats: player, goals, shots = stat if player not in all_games_stats: all_games_stats[player] = [goals, shots] else: stat_list = all_games_stats[player] stat_list[0] += goals stat_list[1] += shotsEntonces, si quieres representar a los jugadores y sus estadísticas como una lista, harías: list(all_games_stats.items())
Puede convertir la lista en un diccionario. (Siempre se puede volver a cambiar una vez hecho) Esto funciona:
player_stats = [['Adam', 5, 10], ['Kyle', 12, 18], ['Jo', 20, 35], ['Adam', 15, 20], ['Charlie', 31, 58], ['Jo', 6, 14], ['Adam', 10, 15]] new_stats = {} for item in player_stats: if not item[0] in new_stats: new_stats[item[0]] = [item[1],item[2]] else: new_stats[item[0]][0] += item[1] new_stats[item[0]][1] += item[2] print(new_stats)