繁体   English   中英

使用linq(C#)比较两个列表的内容,以查看某个特定值是否在某个范围内

[英]Comparing the contents of two lists with linq (C#) to see if one specific value is in a certain range

好吧,我现在已经在我脑海中砸了一天。

我有两个自定义对象列表,两个列表中的一个属性相同。 我需要迭代两个列表,看看属性是否相同。

我可以用嵌套for-each循环来做,但是如果我能用LINQ做同样的事情我会很不情愿(我确信我能做到这一点)。 我已经尝试了几乎所有的东西,但我根本无法找到我正在寻找的解决方案。

这是我用于列表的对象的代码。

public class Game
{
    // Fields
    private short maxPlayers;
    private Team axis;
    private Team allies;

    // Properties
    public string Name { get; set; }
    public short MaxPlayers
    {
        get
        {
            return maxPlayers;
        }
        set
        {
            if (value > 8)
                maxPlayers = 8;
            else if (value < 2)
                maxPlayers = 2;
            else
                maxPlayers = value;
        }
    }
    public short CurrentPlayers
    {
        get
        {
            int players = axis.Players.Count + allies.Players.Count;
            return (short)players;
        }
    }
    public bool IsFull
    {
        get
        {
            if (CurrentPlayers == MaxPlayers)
                return true;
            else
                return false;
        }
    }
    public Team Axis { get; set; }
    public Team Allies { get; set; }
    public List<Player> Players
    {
        // Somehow this does not work either, so I had to stick with one single team in the for-each loops. Ideas to fix?
        get
        {
            if (allies.Players.Count == 0)
                return axis.Players.Concat(allies.Players).ToList();
            else
                return allies.Players.Concat(axis.Players).ToList();

        }
    }

    //Constructor
    public Game()
    {
        axis = new Team();
        allies = new Team();
    }
}

public class Team
{
    public List<Player> Players { get; set; }

    public EFaction Faction { get; set; }

    public enum EFaction
    {
        Allies,
        Axis,
        Random
    }

    public Team()
    {
        Players = new List<Player>();
        Faction = EFaction.Random;
    }
}

public class Player
{
    private int skillRange = 200;

    public string Name { get; set; }
    public int Skill { get; set; }
    public int SkillRange
    {
        get
        {
            return skillRange;
        }
        set
        {
            if (value >= 200)
                skillRange = value;
            else
                skillRange = 200;
        }
    }
}

在启动时,我从数据库填充List并对List执行相同操作。 我想要做的是遍历游戏列表,并将游戏中每个玩家的技能属性与团队中每个玩家的技能属性进行比较。 这是我使用的for-each循环。 这很有效。 但是你清楚地看到我为什么要这么糟糕地削减它。

        // Loop through each player in the Automatch queue.
        foreach (Team team in match.TeamsInQueue)
        {
            // Loop through every game in the Atomatch queue.
            foreach (Game game in match.AvailableGames)
            {
                int teamPlayersInSkillRange = 0;

                // Loop through every player in the team and loop through every player in the game.
                foreach (Player teamPlayer in team.Players)
                {
                    int gamePlayersInSkillRange = 0;
                    foreach (Player gamePlayer in game.Allies.Players)
                    {
                        // Compare beoth skill values. If they are in a certain range increase the counter.
                        if (Math.Abs(teamPlayer.Skill - gamePlayer.Skill) <= 200) // The range is currently set for 200, but I want to make it variable later.
                            gamePlayersInSkillRange++;
                    }

                    // Check if the player in the team is in skill range of the game he wants to join. If yes increase the counter.
                    if (gamePlayersInSkillRange == game.Allies.Players.Count)
                        teamPlayersInSkillRange++;
                  }
                // Check if the whole team is in skill range of the game they want to join. If yes return true.
                if (teamPlayersInSkillRange == team.Players.Count)
                {
                    // ToDo: Implement join process here.
                }
            }
        }

任何帮助,将不胜感激。 谢谢。

对于给定的团队和游戏,如果团队的所有玩家都在所有游戏玩家的技能范围内,您希望团队加入游戏。 这听起来像是All()方法的工作!

// Loop through each player in the Automatch queue.
foreach (Team team in match.TeamsInQueue)
{
    // Loop through every game in the Atomatch queue.
    foreach (Game game in match.AvailableGames)
    {
        bool allInSkillRange = team.Players.All(t =>
            game.Allies.Players.All(g => Math.Abs(t.Skill - g.Skill) <= 200));
        if(allInSkillRange)
        {
            // ToDo: Implement join process here.
        }
    }
}

如果您对将代码转换为LINQ的自动方式感兴趣,请查看Resharper

以下是我提出解决方案的方法。 使用此过程以及熟悉LINQ的方法和获取经验可以使重构更容易。 我不只是看代码并立即想到使用All() 我开始重构较小的部分,然后从那里开始。 阅读完所有代码后,我专注于最内层的循环。

int gamePlayersInSkillRange = 0;
foreach (Player gamePlayer in game.Allies.Players)
{
    // Compare beoth skill values. If they are in a certain range increase the counter.
    if (Math.Abs(teamPlayer.Skill - gamePlayer.Skill) <= 200) // The range is currently set for 200, but I want to make it variable later.
        gamePlayersInSkillRange++;
}

这会计算满足条件的玩家数量,可以将其重构为Count()调用:

int gamePlayersInSkillRange = game.Allies.Players.Count(g => 
    (Math.Abs(teamPlayer.Skill - g.Skill) <= 200);

以下if语句检查gamePlayersInSkillRange是否等于game.Allies.Players中的项目数,这是我们最初计算的列表。 哦,所以我们检查所有列表成员是否满足谓词! 我们可以通过将Count()更改为All()来在LINQ调用中包含该步骤。 这是下一个最内层循环现在的样子:

foreach (Player teamPlayer in team.Players)
{
    bool allGamePlayersInRange = game.Allies.Players.All(g => 
        (Math.Abs(teamPlayer.Skill - g.Skill) <= 200);

    // Check if the player in the team is in skill range of the game he wants to join. If yes increase the counter.
    if (allGamePlayersInRange)
        teamPlayersInSkillRange++;

}

现在这个循环看起来可以重构为Count()调用。 但是如果我们仔细检查它之后的代码,我们就会发现它与我们刚刚重构的循环完全相同,这意味着我们可以直接将其重构为All()调用,完成重构。

尝试这个:

foreach(Team team in match.TeamsInQueue)
{
    if(team.Players.Insersect(match
           .SelectMany(m => m.AvailableGames, g=> g.Allies.Players), 
            new PlayerSkillComparer().Count() == team.Players.Count()) {
         // ToDO: Implement join process here.
    }
}

其中PlayerSkillComparer实现IEqualityComparer<Player> ,如果两个给定的Player对象具有<= 200的技能差异,则其Equals方法返回true。请参阅此处的示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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