2012-02-03 18 views
1

我有一份玩家名单,每名玩家都有一份技能等级列表。 我想要做的是根据与特定搜索列表匹配的评分排序这些玩家。比较整数列表,然后根据相似性排序它们。

下面是四个球员的榜样:

 List<Skill> skillsA = new List<Skill>(); 
     List<Skill> skillsB = new List<Skill>(); 
     List<Skill> skillsC = new List<Skill>(); 
     List<Skill> skillsD = new List<Skill>(); 

     skillsA.Add(new Skill() { Name = "Speed", Value = 1 }); 
     skillsA.Add(new Skill() { Name = "Agility", Value = 5 }); 
     skillsA.Add(new Skill() { Name = "Strength", Value = 3 }); 
     skillsA.Add(new Skill() { Name = "Endurance", Value = 4 }); 

     skillsB.Add(new Skill() { Name = "Speed", Value = 5 }); 
     skillsB.Add(new Skill() { Name = "Agility", Value = 2 }); 
     skillsB.Add(new Skill() { Name = "Strength", Value = 1 }); 
     skillsB.Add(new Skill() { Name = "Endurance", Value = 3 }); 

     skillsC.Add(new Skill() { Name = "Speed", Value = 5 }); 
     skillsC.Add(new Skill() { Name = "Agility", Value = 3 }); 
     skillsC.Add(new Skill() { Name = "Strength", Value = 2 }); 
     skillsC.Add(new Skill() { Name = "Endurance", Value = 2 }); 

     skillsD.Add(new Skill() { Name = "Speed", Value = 1 }); 
     skillsD.Add(new Skill() { Name = "Agility", Value = 2 }); 
     skillsD.Add(new Skill() { Name = "Strength", Value = 5 }); 
     skillsD.Add(new Skill() { Name = "Endurance", Value = 4 }); 

     Player A = new Player() { Skills = skillsA }; 
     Player B = new Player() { Skills = skillsB }; 
     Player C = new Player() { Skills = skillsC }; 
     Player D = new Player() { Skills = skillsD }; 

这将是搜索列表我比较:

 List<Skill> matchSkill = new List<Skill>(); 

     matchSkill.Add(new Skill() { Name = "Speed", Value = 5 }); 
     matchSkill.Add(new Skill() { Name = "Agility", Value = 2 }); 
     matchSkill.Add(new Skill() { Name = "Strength", Value = 1 }); 
     matchSkill.Add(new Skill() { Name = "Endurance", Value = 1 }); 

     SkillSearch SkillSearch = new SkillSearch() { Skills = matchSkill }; 

我应该回来的球员名单下令PlayerB,PlayerC,PlayerD ,玩家A

技能列表将始终是相同的大小和顺序。技能总是在1-5之间。我试图用绝对值来比较这些值之间的差异。例如,如果搜索是针对(3)2和4会比1或5

总之更接近的匹配,如果你只是看它们作为数字数组的你将有:

 search = { 5, 2, 1, 1} 

     playerb = { 5, 2, 1, 3} : difference {0,0,0,2} (2 total) 
     playerc = { 5, 3, 2, 2} : difference {0,1,1,1} (3 total) 
     playerd = { 1, 2, 5, 4} : difference {4,0,4,3} (11 total) 
     playera = { 1, 5, 3, 4} : difference {4,3,2,3} (12 total) 

我将如何使用C#订购这些产品?我更喜欢linq结果。我只是不确定如何得到这些订单。

+0

对不起,由于某种原因,我忘了添加问题... – 2012-02-03 17:28:27

+1

似乎你已选择曼哈顿距离作为你的距离测量。那么,问题是什么?您需要计算两组技能之间绝对差异的总和,并按最低距离对其进行排名。 – Andreas 2012-02-03 18:29:34

回答

3

假设类:

public class Skill 
{ 
    public string Name { get; set; } 
    public int Value { get; set; } 
} 

public class Player 
{ 
    public string Name { get; set; } 
    public ICollection<Skill> Skills { get; set; } 
} 

您可以用collection initializers取代List<T>.Add调用序列:

Player[] players = new Player[] 
{ 
    new Player 
    { 
     Name = "A", 
     Skills = new Skill[] 
     { 
      new Skill { Name = "Speed", Value = 1 }, 
      new Skill { Name = "Agility", Value = 5 }, 
      new Skill { Name = "Strength", Value = 3 }, 
      new Skill { Name = "Endurance", Value = 4 }, 
     } 
    }, 
    new Player 
    { 
     Name = "B", 
     Skills = new Skill[] 
     { 
      new Skill { Name = "Speed", Value = 5 }, 
      new Skill { Name = "Agility", Value = 2 }, 
      new Skill { Name = "Strength", Value = 1 }, 
      new Skill { Name = "Endurance", Value = 3 }, 
     } 
    }, 
    new Player 
    { 
     Name = "C", 
     Skills = new Skill[] 
     { 
      new Skill { Name = "Speed", Value = 5 }, 
      new Skill { Name = "Agility", Value = 3 }, 
      new Skill { Name = "Strength", Value = 2 }, 
      new Skill { Name = "Endurance", Value = 2 }, 
     } 
    }, 
    new Player 
    { 
     Name = "D", 
     Skills = new Skill[] 
     { 
      new Skill { Name = "Speed", Value = 1 }, 
      new Skill { Name = "Agility", Value = 2 }, 
      new Skill { Name = "Strength", Value = 5 }, 
      new Skill { Name = "Endurance", Value = 4 }, 
     } 
    } 
}; 

Skill[] matchSkills = new Skill[] 
{ 
    new Skill { Name = "Speed", Value = 5 }, 
    new Skill { Name = "Agility", Value = 2 }, 
    new Skill { Name = "Strength", Value = 1 }, 
    new Skill { Name = "Endurance", Value = 1 }, 
}; 

接下来,你应该建立在matchSkills收集Dictionary<string, Skill>;这将允许您按名称快速查找技巧:

var matchSkillsDictionary = matchSkills.ToDictionary(matchSkill => matchSkill.Name); 

最后,你可以使用LINQ OrderBy操作你的球员在递减的技能差总和值进行排序。我们将用两个中间的功能,以帮助使事情变得清晰:

Func<Skill, int> getSkillDiff = skill => Math.Abs(skill.Value - matchSkillsDictionary[skill.Name].Value); 
Func<Player, int> getPlayerDiff = player => player.Skills.Sum(getSkillDiff); 
IEnumerable<Player> orderedPlayers = players.OrderBy(getPlayerDiff); 
+0

工程就像一个魅力!如果我的应用程序需要从循环中添加硬编码(如示例),我会使用集合初始值设定项。玩家和技能最初将从实体框架结果填充。我最初的代码会利用一个proc,但是有一个匹配的searchskills列表可以比较容易地进行比较。非常感谢。 – 2012-02-03 19:09:20

+1

使意义重新收集初始值设定项;我应该假设你不会使用硬编码数据:-) – Douglas 2012-02-03 19:26:20

3

试试这个:

players.OrderBy(player => player.Skills.Zip(matchSkills, (pl, sr) => Math.Abs(pl.Value - sr.Value)).Sum()) 

球员是数组{A,B,C,d}。

修复了道格拉斯遗漏的“.Skills”和“.Value”部件。

+0

运算符不能应用于“Math.Abs​​(pl-sr)”?也许我没有正确分配搜索? – 2012-02-03 19:13:09

+0

直到星期天才能检查,所以你可以尝试自己看看。这里是Zip文档:http://msdn.microsoft.com/en-us/library/dd267698.aspx。我会检查我的答案,并会更新我的帖子。 – 2012-02-03 19:21:48

2

回复梅德Polyanitsa:

我想这是你的意思是:

players.OrderBy(player => player.Skills.Zip(matchSkills, (pl, sr) => Math.Abs(pl.Value - sr.Value)).Sum()); 

但是,你假定所有玩家的技能(和匹配组)是总是以相同的顺序。如果一个玩家定义了Speed, Agility, Strength, Endurance,另一个玩家不能定义Agility, Speed, Strength, Endurance

编辑:其实,你的假设是正确的。问题指出:“技能列表将始终是相同的大小和顺序。“我很抱歉失踪。

在这种情况下,您的解决方案可能比我的原始提案更有效,因为它避免了名称查找的开销。

+0

谢谢,不知何故错过了该部分的问题。是的,我同意你的技能顺序。 – 2012-02-03 19:55:26

+0

无论如何,拥有简单明了的解决方案和更加清晰可扩展的解决方案总是不错的。 – 2012-02-03 20:36:13

相关问题