public IList <TeamData> GetTeamData() { SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var teams = new TeamGateway(connection, transaction).GetTeamsWithBouts(); var leagues = new LeagueGateway(connection, transaction).GetAllLeagues().ToDictionary(l => l.ID); transaction.Commit(); connection.Close(); List <TeamData> list = new List <TeamData>(200); foreach (Team team in teams) { list.Add(new TeamData { LeagueID = team.LeagueID, LeagueName = leagues[team.LeagueID].Name, TeamID = team.ID, TeamName = team.Name, TeamType = team.TeamType }); } return(list); }
public void Import(string connectionString, StatbookModel statbook, bool assumeATeams) { _connection = new SqlConnection(connectionString); try { _connection.Open(); _transaction = _connection.BeginTransaction(); // insert leagues LeagueGateway leagueGateway = new LeagueGateway(_connection, _transaction); var leagues = leagueGateway.GetAllLeagues(); League homeLeague = leagues.FirstOrDefault(l => l.Name.ToLower() == statbook.HomeTeam.LeagueName.ToLower()); League awayLeague = leagues.FirstOrDefault(l => l.Name.ToLower() == statbook.AwayTeam.LeagueName.ToLower()); int maxID = leagues.Select(l => l.ID).Max(); if (homeLeague == null) { homeLeague = leagueGateway.GetLeague(maxID + 1, statbook.HomeTeam.LeagueName, statbook.Date, false); maxID++; } if (awayLeague == null) { awayLeague = leagueGateway.GetLeague(maxID + 1, statbook.AwayTeam.LeagueName, statbook.Date, false); maxID++; } // insert teams TeamGateway teamGateway = new TeamGateway(_connection, _transaction); Team homeTeam, awayTeam; if (assumeATeams) { homeTeam = teamGateway.GetATeam(homeLeague.ID); awayTeam = teamGateway.GetATeam(awayLeague.ID); } else { homeTeam = teamGateway.GetTeam(statbook.HomeTeam.Name, homeLeague.ID, "A", false); awayTeam = teamGateway.GetTeam(statbook.AwayTeam.Name, awayLeague.ID, "A", false); } // insert bout BoutGateway boutGateway = new BoutGateway(_connection, _transaction); if (!boutGateway.DoesBoutExist(homeTeam.ID, awayTeam.ID, statbook.Date)) { Bout bout = boutGateway.GetBout(homeTeam.ID, awayTeam.ID, statbook.Date); BoutDataImport(statbook, bout, homeTeam, awayTeam); } else { // bout already exists Console.WriteLine(string.Format("Bout between {0} and {1} on {2} already exists.", homeTeam.Name, awayTeam.Name, statbook.Date)); } _transaction.Commit(); } finally { _connection.Close(); } }
public IList <Dictionary <int, PlayerPerformance> > GetAllPlayerPointPerformances(int numberOfIterations) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetAllPlayers().GroupBy(p => p.ID).ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID)); var jams = new JamGateway(connection, transaction).GetAllJams().OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetAllJamPlayerEffectiveness(); var jamData = new JamDataGateway(connection, transaction).GetJamTeamDataForYear(STATS_START_DATE.Year) .GroupBy(jd => jd.JamID) .ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.TeamID)); var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetAllPenalties() .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetAllPenaltyGroups(); Dictionary <int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); Dictionary <int, Dictionary <int, JamPlayer> > jamPlayerMap = new JamPlayerGateway(connection, transaction).GetJamPlayers() .GroupBy(jp => jp.JamID) .ToDictionary(g => g.Key, g => g.ToDictionary(g2 => g2.PlayerID)); transaction.Commit(); connection.Close(); Dictionary <FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator ppcCalc = new PenaltyCostCalculator(_connectionString); Dictionary <int, double> groupPenaltyCostMap = PenaltyCostCalculator.CalculatePointCosts(jamData, jamPlayerMap, pgs, boxTimeEstimates, sss); Dictionary <int, double> jamTotalPortionMap = new Dictionary <int, double>(300); var previousResult = GenerateInitialPlayerPerformance(players, jams, jpe, jamData, teams, bouts, penalties, pgs, avgPenCost, medians, groupPenaltyCostMap, jamTotalPortionMap); List <Dictionary <int, PlayerPerformance> > result = new List <Dictionary <int, PlayerPerformance> >(numberOfIterations); result.Add(previousResult); int i = 0; while (i < numberOfIterations) { previousResult = GeneratePlayerPerformanceIteration(previousResult, jams, jamData, jamTotalPortionMap, jpe, avgPenCost); result.Add(previousResult); i++; } return(result); }
public void Import(string connectionString, StatbookModel statbook) { _connection = new SqlConnection(connectionString); try { _connection.Open(); _transaction = _connection.BeginTransaction(); // insert leagues LeagueGateway leagueGateway = new LeagueGateway(_connection, _transaction); var leagues = leagueGateway.GetAllLeagues(); League homeLeague = leagues.FirstOrDefault(l => l.Name.ToLower() == statbook.HomeTeam.LeagueName.ToLower()); League awayLeague = leagues.FirstOrDefault(l => l.Name.ToLower() == statbook.AwayTeam.LeagueName.ToLower()); int maxID = leagues.Select(l => l.ID).Max(); if (homeLeague == null || awayLeague == null) { throw new InvalidOperationException("Bad league name"); } // for the basic importer, we'll just take whatever A team this league has, rather than worrying about validating the team name TeamGateway teamGateway = new TeamGateway(_connection, _transaction); Team homeTeam = teamGateway.GetATeam(homeLeague.ID); Team awayTeam = teamGateway.GetATeam(awayLeague.ID); // insert bout BoutGateway boutGateway = new BoutGateway(_connection, _transaction); if (!boutGateway.DoesBoutExist(homeTeam.ID, awayTeam.ID, statbook.Date)) { Bout bout = boutGateway.GetBout(homeTeam.ID, awayTeam.ID, statbook.Date); BoutDataImport(statbook, bout, homeTeam, awayTeam); } else { // bout already exists Console.WriteLine(string.Format("Bout between {0} and {1} on {2} already exists.", homeTeam.Name, awayTeam.Name, statbook.Date)); } _transaction.Commit(); } finally { _connection.Close(); } }
public void Setup() { _teamGateway = new TeamGateway(DatabaseContext); }
public TeamService() : base(new TeamGateway(), new TeamValidator()) { _gateway = new TeamGateway(); _schoolGateway = new BaseGateway <School>(); }
public IList <TeamRating> GetTeamRatings() { SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); // attempt to get the rankings data from the db TeamRatingGateway trGateway = new TeamRatingGateway(connection, transaction); TeamGateway teamGateway = new TeamGateway(connection, transaction); LeagueGateway leagueGateway = new LeagueGateway(connection, transaction); var teamRankings = trGateway.GetCurrentTeamRatings(); if (!teamRankings.Any() || DateTime.Now.Subtract(teamRankings[0].AddedDate).TotalDays > 30) { var teams = teamGateway.GetAllWftdaTeams(); var leagues = leagueGateway.GetAllLeagues(); var teamMapper = new TeamMapperGateway(connection, transaction).GetAllTeamMappers(); var wftdaData = GetWftdaRankingsData(); var ftsData = GetFtsRankingsData(); teamRankings = new List <TeamRating>(250); var leftOut = new List <WftdaRankingData>(); foreach (WftdaRankingData wftda in wftdaData) { var fts = ftsData.FirstOrDefault(f => string.Equals(wftda.TeamName.Substring(0, 10), f.TeamName.Substring(0, 10), StringComparison.OrdinalIgnoreCase)); if (fts != null) { teamRankings.Add(new TeamRating { FtsRank = fts.Rank, FtsScore = fts.Rating, TeamID = 0, TeamName = wftda.TeamName, WftdaRank = wftda.Rank, WftdaScore = wftda.RatingScore, WftdaStrength = wftda.Strength }); } else { // try the team mapper? TeamMapper map = teamMapper.FirstOrDefault(tm => string.Equals(tm.TeamSpelling, wftda.TeamName, StringComparison.OrdinalIgnoreCase)); if (map != null) { var otherMaps = teamMapper.Where(tm => tm.TeamID == map.TeamID).Select(tm => tm.TeamSpelling); fts = ftsData.FirstOrDefault(f => otherMaps.Contains(f.TeamName)); if (fts != null) { teamRankings.Add(new TeamRating { FtsRank = fts.Rank, FtsScore = fts.Rating, TeamID = map.TeamID, TeamName = wftda.TeamName, WftdaRank = wftda.Rank, WftdaScore = wftda.RatingScore, WftdaStrength = wftda.Strength }); } else { leftOut.Add(wftda); } } } } List <TeamRating> leftOvers = new List <TeamRating>(); foreach (TeamRating teamRating in teamRankings) { if (teamRating.TeamID > 0) { continue; } var team = teams.FirstOrDefault(t => string.Equals(t.Name, teamRating.TeamName, StringComparison.OrdinalIgnoreCase)); if (team != null) { teamRating.TeamID = team.ID; } else { var league = leagues.FirstOrDefault(l => string.Equals(l.Name, teamRating.TeamName, StringComparison.OrdinalIgnoreCase)); if (league != null) { team = teams.First(t => t.LeagueID == league.ID); teamRating.TeamID = team.ID; } else { // try the team mapper? TeamMapper map = teamMapper.FirstOrDefault(tm => string.Equals(tm.TeamSpelling, teamRating.TeamName, StringComparison.OrdinalIgnoreCase)); if (map != null) { teamRating.TeamID = map.TeamID; } // TODO: else, create the League and the team? The nature of leagueID makes that tough... } } } trGateway.InsertTeamRatings(teamRankings.Where(tr => tr.TeamID != 0).ToList()); } transaction.Commit(); connection.Close(); return(teamRankings); }
public IList <PlayerPerformance> GetPlayerPointPerformancesForTeam(int teamID) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetPlayersForTeam(teamID).ToDictionary(p => p.ID); var jams = new JamGateway(connection, transaction).GetJamsForTeamAfterDate(teamID, STATS_START_DATE).OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetJamPlayerEffectivenessForTeam(teamID); var jdg = new JamDataGateway(connection, transaction); var jamTeamData = jdg.GetJamDataForTeam(teamID).ToDictionary(jd => jd.JamID); var jamData = jdg.GetAllJamData().ToDictionary(jd => jd.JamID); foreach (JamTeamData jtd in jamTeamData.Values) { jtd.Year = jamData[jtd.JamID].PlayDate.Year; } var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetPenaltiesForTeam(teamID) .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetPenaltyGroupsForTeamAfterDate(teamID, STATS_START_DATE); Dictionary <int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); transaction.Commit(); connection.Close(); Dictionary <FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator ppcCalc = new PenaltyCostCalculator(_connectionString); Dictionary <int, double> groupPenaltyCostMap = ppcCalc.CalculatePointCostsForTeam(jamTeamData, pgs, boxTimeEstimates, sss); Dictionary <int, PlayerPerformance> pps = new Dictionary <int, PlayerPerformance>(25); Dictionary <int, double> jamTotalPortionMap = new Dictionary <int, double>(300); // we use "jam portions" to divide up the total value of the jam among participating players // we give jammers an additional multiplier to their jam portions, based on year, to represent their greater impact on team success foreach (Jam jam in jams) { var pe = jpe[jam.ID]; foreach (JamPlayerEffectiveness eff in pe.Values) { // get/set PlayerPerformance object if (!pps.ContainsKey(eff.PlayerID)) { pps[eff.PlayerID] = new PlayerPerformance { Player = players[eff.PlayerID], Bouts = new List <BoutPerformance>() }; } PlayerPerformance curPP = pps[eff.PlayerID]; // get/set BoutPerformance object Bout bout = bouts[jam.BoutID]; BoutPerformance bp = null; if (!curPP.Bouts.Any() || curPP.Bouts.Last().BoutID != bout.ID) { bp = new BoutPerformance { BoutID = bout.ID, AwayTeamName = teams[bout.AwayTeamID].Name, HomeTeamName = teams[bout.HomeTeamID].Name, BoutDate = bout.BoutDate, Jams = new List <JamPerformance>() }; curPP.Bouts.Add(bp); } else { bp = curPP.Bouts.Last(); } JamTeamData jd = jamTeamData[jam.ID]; int penaltyCount = penalties.ContainsKey(jam.ID) && penalties[jam.ID].ContainsKey(eff.PlayerID) ? penalties[jam.ID][eff.PlayerID].Count() : 0; JamPerformance jp = new JamPerformance { BlockerJamPercentage = eff.IsJammer ? 0 : eff.JamPortion, DeltaPercentile = eff.BaseQuality, IsFirstHalf = jam.IsFirstHalf, JamID = jam.ID, JammerJamPercentage = eff.IsJammer ? eff.JamPortion : 0, JamNumber = jam.JamNumber, JamPenalties = penaltyCount, MedianDelta = medians[jd.FoulComparison], PenaltyCost = 0, PointDelta = jd.PointDelta }; double jammerRatio = bouts[jamBoutMap[jam.ID]].BoutDate.Year == 2019 ? 2.0 : 4.0; if (jamTotalPortionMap.ContainsKey(jam.ID)) { jamTotalPortionMap[jam.ID] += eff.IsJammer ? eff.JamPortion * jammerRatio : eff.JamPortion; } else { jamTotalPortionMap[jam.ID] = eff.IsJammer ? eff.JamPortion * jammerRatio : eff.JamPortion; } bp.Jams.Add(jp); } } foreach (PenaltyGroup pg in pgs) { foreach (Penalty p in pg.Penalties) { if (jams.Any(j => j.ID == p.JamID)) { JamPerformance jp = pps[p.PlayerID].Bouts.SelectMany(b => b.Jams).Where(j => j.JamID == p.JamID).First(); jp.PenaltyCost += groupPenaltyCostMap[pg.GroupID]; } } } foreach (PlayerPerformance pp in pps.Values) { RollUpPlayerPerformance(avgPenCost, jamTotalPortionMap, pp); } CalculateTeamAverages(pps, bouts); foreach (PlayerPerformance pp in pps.Values) { pp.BlockerPerformance.PlayerValueVersusTeamAverage = pp.Bouts.Sum(b => b.BlockerPerformance.PlayerValueVersusTeamAverage); pp.JammerPerformance.PlayerValueVersusTeamAverage = pp.Bouts.Sum(b => b.JammerPerformance.PlayerValueVersusTeamAverage); } return(pps.Values.ToList()); }
public IList <PlayerPerformance> GetPlayerValuePerformancesForTeam(int teamID) { // pull data SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); var players = new PlayerGateway(connection, transaction).GetPlayersForTeam(teamID).ToDictionary(p => p.ID); var jams = new JamGateway(connection, transaction).GetJamsForTeamAfterDate(teamID, new DateTime(2016, 1, 1)).OrderBy(j => j.ID); var jamBoutMap = jams.ToDictionary(j => j.ID, j => j.BoutID); var jpe = new JamPlayerEffectivenessGateway(connection, transaction).GetJamPlayerEffectivenessForTeam(teamID); var jamData = new JamDataGateway(connection, transaction).GetJamDataForTeam(teamID).ToDictionary(jd => jd.JamID); var teams = new TeamGateway(connection, transaction).GetAllTeams().ToDictionary(t => t.ID); var bouts = new BoutGateway(connection, transaction).GetBouts().ToDictionary(t => t.ID); var penalties = new PenaltyGateway(connection, transaction).GetPenaltiesForTeam(teamID) .GroupBy(p => p.JamID) .ToDictionary( g => g.Key, g => g.GroupBy(g2 => g2.PlayerID).ToDictionary(g3 => g3.Key, g3 => g3.ToList())); var pgs = new PenaltyGroupGateway(connection, transaction).GetPenaltyGroupsForTeam(teamID); Dictionary <int, int> boxTimeEstimates = new BoxTimeEstimateGateway(connection, transaction).GetAllBoxTimeEstimates(); Dictionary <FoulComparison, Dictionary <int, float> > sss = new SituationalScoreGateway(connection, transaction).GetAllSituationalScores(); Dictionary <int, double> jte = new JamTeamEffectivenessGateway(connection, transaction).GetJamTeamEffectivenessForTeam(teamID); AveragePenaltyCostPerJam avgPenCost = new AveragePenaltyCostGateway(connection, transaction).GetAveragePenaltyCost(); transaction.Commit(); connection.Close(); Dictionary <FoulComparison, float> medians = CalculateMedianScores(sss); PenaltyCostCalculator pcCalc = new PenaltyCostCalculator(_connectionString); Dictionary <int, double> groupPenaltyCostMap = pcCalc.CalculateValueCostsForTeam(jamData, pgs, boxTimeEstimates, sss, jte); Dictionary <int, PlayerPerformance> ppMap = new Dictionary <int, PlayerPerformance>(25); Dictionary <int, double> jamTotalPortionMap = new Dictionary <int, double>(300); foreach (Jam jam in jams) { var pe = jpe[jam.ID]; foreach (JamPlayerEffectiveness eff in pe.Values) { // get/set PlayerPerformance object if (!ppMap.ContainsKey(eff.PlayerID)) { ppMap[eff.PlayerID] = new PlayerPerformance { Player = players[eff.PlayerID], Bouts = new List <BoutPerformance>() }; } PlayerPerformance curPP = ppMap[eff.PlayerID]; // get/set BoutPerformance object Bout bout = bouts[jam.BoutID]; BoutPerformance bp = null; if (!curPP.Bouts.Any() || curPP.Bouts.Last().BoutDate != bout.BoutDate || curPP.Bouts.Last().HomeTeamName != teams[bout.HomeTeamID].Name || curPP.Bouts.Last().AwayTeamName != teams[bout.AwayTeamID].Name) { bp = new BoutPerformance { AwayTeamName = teams[bout.AwayTeamID].Name, HomeTeamName = teams[bout.HomeTeamID].Name, BoutDate = bout.BoutDate, Jams = new List <JamPerformance>() }; curPP.Bouts.Add(bp); } else { bp = curPP.Bouts.Last(); } JamTeamData jd = jamData[jam.ID]; int penaltyCount = penalties.ContainsKey(jam.ID) && penalties[jam.ID].ContainsKey(eff.PlayerID) ? penalties[jam.ID][eff.PlayerID].Count() : 0; JamPerformance jp = new JamPerformance { BlockerJamPercentage = eff.IsJammer ? 0 : eff.JamPortion, DeltaPercentile = eff.BaseQuality, IsFirstHalf = jam.IsFirstHalf, JamID = jam.ID, JammerJamPercentage = eff.IsJammer ? eff.JamPortion : 0, JamNumber = jam.JamNumber, JamPenalties = penaltyCount, MedianDelta = medians[jd.FoulComparison], PenaltyCost = 0, PointDelta = jd.PointDelta }; if (jamTotalPortionMap.ContainsKey(jam.ID)) { jamTotalPortionMap[jam.ID] += eff.IsJammer ? eff.JamPortion * 4 : eff.JamPortion; } else { jamTotalPortionMap[jam.ID] = eff.IsJammer ? eff.JamPortion * 4 : eff.JamPortion; } bp.Jams.Add(jp); } } foreach (PenaltyGroup pg in pgs) { foreach (Penalty p in pg.Penalties) { JamPerformance jp = ppMap[p.PlayerID].Bouts.SelectMany(b => b.Jams).Where(j => j.JamID == p.JamID).First(); jp.PenaltyCost += groupPenaltyCostMap[pg.GroupID]; } } foreach (PlayerPerformance pp in ppMap.Values) { pp.BlockerPerformance = new RolledUpPerformanceData(); pp.JammerPerformance = new RolledUpPerformanceData(); foreach (BoutPerformance bp in pp.Bouts) { bp.BlockerPerformance = new RolledUpPerformanceData(); bp.JammerPerformance = new RolledUpPerformanceData(); foreach (JamPerformance jp in bp.Jams) { double averagePenaltyCost = jp.JammerJamPercentage > 0 ? avgPenCost.JammerValueCost : avgPenCost.BlockerValueCost; double jamShare = (jp.JammerJamPercentage * 4 + jp.BlockerJamPercentage) / jamTotalPortionMap[jp.JamID]; jp.DeltaPortionVersusMedian = (jp.DeltaPercentile - 0.5) * jamShare; jp.PlayerValue = jp.DeltaPortionVersusMedian + jp.PenaltyCost - averagePenaltyCost; var rollUp = jp.JammerJamPercentage > 0 ? bp.JammerPerformance : bp.BlockerPerformance; rollUp.TotalJamPortions += jp.JammerJamPercentage + jp.BlockerJamPercentage; rollUp.TotalPenalties += jp.JamPenalties; rollUp.TotalPenaltyCost += jp.PenaltyCost; rollUp.TotalPointsVersusMedian += jp.DeltaPortionVersusMedian; rollUp.TotalPlayerValue += jp.PlayerValue; } pp.BlockerPerformance.TotalJamPortions += bp.BlockerPerformance.TotalJamPortions; pp.BlockerPerformance.TotalPenalties += bp.BlockerPerformance.TotalPenalties; pp.BlockerPerformance.TotalPenaltyCost += bp.BlockerPerformance.TotalPenaltyCost; pp.BlockerPerformance.TotalPointsVersusMedian += bp.BlockerPerformance.TotalPointsVersusMedian; pp.BlockerPerformance.TotalPlayerValue += bp.BlockerPerformance.TotalPlayerValue; pp.JammerPerformance.TotalJamPortions += bp.JammerPerformance.TotalJamPortions; pp.JammerPerformance.TotalPenalties += bp.JammerPerformance.TotalPenalties; pp.JammerPerformance.TotalPenaltyCost += bp.JammerPerformance.TotalPenaltyCost; pp.JammerPerformance.TotalPointsVersusMedian += bp.JammerPerformance.TotalPointsVersusMedian; pp.JammerPerformance.TotalPlayerValue += bp.JammerPerformance.TotalPlayerValue; } } return(ppMap.Values.ToList()); }