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

本文关键字:一个 是否 范围内 比较 linq 两个 列表 | 更新日期: 2023-09-27 17:49:27

好了,为了今天的好心情,我已经摔碎了脑袋。

我有两个自定义对象列表,在两个列表中具有相同的属性。我需要遍历两个列表,看看属性是否相同。

我可以用嵌套的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.
                }
            }
        }

任何帮助都会很感激。谢谢。

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

对于给定的团队和游戏,如果该团队的所有玩家的技能都在所有游戏玩家的技能范围内,那么您希望该团队加入游戏。这听起来像是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中的物品数量。玩家,这是我们最初计算的列表。哦,所以我们要检查所有的列表成员是否满足谓词!我们可以通过将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对象具有技能差异,则其Equals方法返回true <= 200。

相关文章: