比较整数列表,然后根据相似性对它们进行排序。

时间:2012-02-03 17:16:54

标签: c# .net linq

我有一个玩家列表,每个玩家都包含技能等级列表。 我想要做的是根据与特定搜索列表匹配的评级来命令这些玩家。

以下是四名球员的例子:

        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,PlayerA

的玩家列表

技能列表将始终具有相同的大小和相同的顺序。技能总是从1-5。我尝试使用绝对值比较值之间的差异。例如,如果搜索是针对a(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的结果。我只是不确定如何订购这些产品。

3 个答案:

答案 0 :(得分: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 },
};

接下来,您应该为Dictionary<string, Skill>集合构建matchSkills;这将允许您通过名称快速查找技能:

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);

答案 1 :(得分:3)

试试这个:

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

玩家是阵列{A,B,C,D}。

通过道格拉斯修复了丢失的“.Skills”和“.Value”部分。

答案 2 :(得分:2)

回复给Dmitry 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

修改:实际上,您的假设是正确的。问题是:“技能列表总是大小相同,顺序相同。”我很抱歉错过了。

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