好的,我现在已经在我脑海中砸了一天。
我有两个自定义对象列表,两个列表中的一个属性相同。我需要遍历两个列表并查看属性是否相同。
我可以用嵌套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.
}
}
}
任何帮助将不胜感激。感谢。
答案 0 :(得分:2)
对于给定的团队和游戏,如果所有团队的玩家都在所有游戏玩家的技能范围内,您希望团队加入游戏。这听起来像是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()
调用,从而完成重构。
答案 1 :(得分:0)
试试这个:
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>
,Equals
方法如果两个给定的Player
对象具有技能差异&lt; = 200,则返回true。查看示例{{3 }}