简体   繁体   English

从另一个列表建立列表

[英]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:我认为你可以这样做:

  1. Build a list of the 14 cheapest items.列出 14 种最便宜的物品。
  2. Pick the highest value, so long as the remaining space is greater than the total of the 14 cheapest.选择最高值,只要剩余空间大于 14 个最便宜的总和。
  3. Repeat the above, skipping any players that won't fit.重复上述操作,跳过任何不适合的玩家。
  4. Fill the remaining places with players from the 'cheapest' list.用“最便宜”列表中的玩家填充剩余的位置。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM