[英]Build up List from another List
I've got a list of Players.我有一份球员名单。 Each Player has a Marketvalue.每个玩家都有一个市场价值。 I need to build up a second list which iterates through the player list and builds up a team.我需要建立第二个列表,它遍历玩家列表并建立一个团队。 The tricky thing is the new team should have at least 15 players and a maximum Marketvalue of 100 Mio +/- 1%.棘手的是新团队应该有至少 15 名球员和 100 Mio +/- 1% 的最大市值。
Does anyone know how to do that elegantly?有谁知道如何优雅地做到这一点?
private Result<List<Player>> CreateRandomTeam(List<Player> players, int startTeamValue)
{
// start formation 4-4-2
// Threshold tw 20 mio defender 40 mio Midfielder 40 Mio Striker 50 Mio
var playerKeeperList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Keeper);
var playerDefenderList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Defender);
var playerMidfieldList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Midfield);
var playerStrikerList = players.FindAll(p => p.PlayerPosition == PlayerPosition.Striker);
List<Player> keeperPlayers = AddRandomPlayers(playerKeeperList, 2, 0, 20000000);
List<Player> defenderPlayers = AddRandomPlayers(playerDefenderList, 4, 0, 40000000);
List<Player> midfieldPlayers = AddRandomPlayers(playerMidfieldList, 4, 0, 40000000);
List<Player> strikerPlayers = AddRandomPlayers(playerStrikerList, 2, 0, 50000000);
List<Player> team = new List<Player>();
team.AddRange(keeperPlayers);
team.AddRange(defenderPlayers);
team.AddRange(midfieldPlayers);
team.AddRange(strikerPlayers);
var currentTeamValue = team.Sum(s => s.MarketValue);
var budgetLeft = startTeamValue - currentTeamValue;
players.RemoveAll(p => team.Contains(p));
var player1 = AddRandomPlayers(players, 2, 0, budgetLeft);
team.AddRange(player1);
players.RemoveAll(p => player1.Contains(p));
currentTeamValue = team.Sum(t => t.MarketValue);
budgetLeft = startTeamValue - currentTeamValue;
var player2 = players.Aggregate((x, y) => Math.Abs(x.MarketValue - budgetLeft) < Math.Abs(y.MarketValue - budgetLeft) ? x : y);
team.Add(player2);
players.Remove(player2);
return Result<List<Player>>.Ok(team);
}
private static List<Player> AddRandomPlayers(List<Player> players, int playerCount, double minMarketValue, double threshold)
{
// TODO: AYI Implement Random TeamName assign logic
Random rnd = new Random();
var team = new List<Player>();
double assignedTeamValue = 0;
while (team.Count < playerCount)
{
var index = rnd.Next(players.Count);
var player = players[index];
if ((assignedTeamValue + player.MarketValue) <= threshold)
{
team.Add(player);
players.RemoveAt(index);
assignedTeamValue += player.MarketValue;
}
}
return team;
}`
This isn't really a C# question so much as an algorithm question, so there may be a better place for it.这不是一个真正的 C# 问题,而是一个算法问题,因此可能有更好的地方。 AIUI, you want to pick 15 numbers from a list, such that the total adds up to 99-101. AIUI,你想从一个列表中选择 15 个数字,这样总和是 99-101。
It's likely that there are many solutions, all equally valid.很可能有许多解决方案,它们都同样有效。
I think you could do it like this:我认为你可以这样做:
This will probably give you a team containing the best and worst players, and one middle-ranking player that just fits.这可能会给你一个包含最好和最差球员的球队,以及一个刚好适合的中级球员。
If you want to do some more research, this sounds like a variant of the coin change problem .如果你想做更多的研究,这听起来像是硬币找零问题的一个变种。
Just to show my solution if someone need's it.如果有人需要,只是为了展示我的解决方案。
var selection = new EliteSelection();
var crossover = new OnePointCrossover(0);
var mutation = new UniformMutation(true);
var fitness = new TeamFitness(players, startTeamValue);
var chromosome = new TeamChromosome(15, players.Count);
var population = new Population(players.Count, players.Count, chromosome);
var ga = new GeneticAlgorithm(population, fitness, selection, crossover, mutation)
{
Termination = new GenerationNumberTermination(100)
};
ga.Start();
var bestChromosome = ga.BestChromosome as TeamChromosome;
var team = new List<Player>();
if (bestChromosome != null)
{
for (int i = 0; i < bestChromosome.Length; i++)
{
team.Add(players[(int) bestChromosome.GetGene(i).Value]);
}
// Remove assigned player to avoid duplicate assignment
players.RemoveAll(p => team.Contains(p));
return Result<List<Player>>.Ok(team);
}
return Result<List<Player>>.Error("Chromosome was null!");
There is a fitness method which handles the logic to get the best result.有一种适应度方法可以处理逻辑以获得最佳结果。
class TeamFitness : IFitness
{
private readonly List<Player> _players;
private readonly int _startTeamValue;
private List<Player> _selected;
public TeamFitness(List<Player> players, int startTeamValue)
{
_players = players;
_startTeamValue = startTeamValue;
}
public double Evaluate(IChromosome chromosome)
{
double f1 = 9;
_selected = new List<Player>();
var indexes = new List<int>();
foreach (var gene in chromosome.GetGenes())
{
indexes.Add((int)gene.Value);
_selected.Add(_players[(int)gene.Value]);
}
if (indexes.Distinct().Count() < chromosome.Length)
{
return int.MinValue;
}
var sumMarketValue = _selected.Sum(s => s.MarketValue);
var targetValue = _startTeamValue;
if (sumMarketValue < targetValue)
{
f1 = targetValue - sumMarketValue;
}else if (sumMarketValue > targetValue)
{
f1 = sumMarketValue - targetValue;
}
else
{
f1 = 0;
}
var keeperCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Keeper);
var strikerCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Striker);
var defCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Defender);
var middleCount = _selected.Count(s => s.PlayerPosition == PlayerPosition.Midfield);
var factor = 0;
var penaltyMoney = 10000000;
if (keeperCount > 2)
{
factor += (keeperCount - 2) * penaltyMoney;
}
if (keeperCount == 0)
{
factor += penaltyMoney;
}
if (strikerCount < 2)
{
factor += (2 - strikerCount) * penaltyMoney;
}
if (middleCount < 4)
{
factor += (4 - middleCount) * penaltyMoney;
}
if (defCount < 4)
{
factor += (4 - defCount) * penaltyMoney;
}
return 1.0 - (f1 + factor);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.