我有一系列抽象类运动员。
{
athletes[0] = new BobSledder("Bobby", "Ben and Bill");
athletes[1] = new BobSledder("Burt", "Bonnie and Baek");
athletes[2] = new BobSledder("Barnie", "Blues and Bart");
athletes[3] = new Skier("Sally", "downhill");
athletes[4] = new Skier("Sarah", "downhill");
athletes[5] = new Skier("Sam", "downhill");
athletes[6] = new IceSkater("Suzy", "blue");
athletes[7] = new IceSkater("Sullie", "red");
athletes[8] = new IceSkater("Sierra", "orange");
}
运动员课程中有一个名为averageScore的字段。我为每个不同的孩子类型设有基于运动员的儿童班。我希望能够找到数组中每个子类型的前3个averageScores。如果增加更多运动员,我希望能够仍然只能找到前3名。我将如何做到这一点?对不起,我对编程很新,而且以前从未使用过子类型。我不知道从哪里开始。
public abstract class Athlete
{
string name;
int eventsRun;
int lastScore;
int runningTotal;
double averageScore;
public Athlete()
{
}
public Athlete(string name)
{
this.name = name;
}
public string Name { get { return name; } }
public int EventsRun { get { return eventsRun; } }
public int LastScore
{
get { return lastScore; }
set
{
lastScore = value;
eventsRun++;
runningTotal += lastScore;
averageScore = runningTotal / eventsRun;
}
}
public double AverageScore { get { return averageScore; } }
答案 0 :(得分:2)
在.NET 3.5或更高版本中:
var topThreePerSubtype = athletes.GroupBy(x => x.GetType()).Select(g => g.OrderByDescending(x => x.averageScores).Take(3));
这实际上会返回IEnumerable
IEnumerable<Athlete>
,这可能不是最好的。我建议您使用TopThree类或类似属性来表示生成的实例。
这是一个(过于简化的)示例:
public class TopThree
{
public Type SubType {get; set;}
public IEnumerable<Athlete> Athletes {get; set;}
}
(...)
var topThreePerSubtype = athletes.GroupBy(x => x.GetType()).Select(g => new TopThree() { SubType = g.Key, Athletes = g.OrderByDescending(x => x.AverageScores).Take(3)});
这种方法的优点在于即使您添加了一个全新的学科,它也能够为您创建另一个前三个对象。不需要额外的代码。
当然,因为这会使用LINQ扩展,所以你必须确保在文件的顶部有这个:
using System.Linq;
答案 1 :(得分:0)
首先,我会使用一个运动员名单,而不是阵列,因为你希望能够改变运动员的数量,只有当他们内部的数字不会改变时才能使用阵列。
那么你有:
List<Athlete> athletes = new List<Athlete>{/*Whatever athlete's you're adding at the start*/};
或
List<Athlete> athletes = new List<Athlete>();
athletes.Add(new BobSledder("Bobby", "Ben and Bill"));
...
这使您可以更轻松地在运行时更改运动员的数量。通过他们的运动来分离每个运动员也可能更容易,而不是将它们全部放在一个列表/阵列中,因为它最终可能更清洁或更简单,但我不确定你的最终目标是什么所以我不能确定哪种方式更好。如果这不是你需要根据他们各自的运动来对付运动员的唯一地方,你可能想要考虑将它们分成单独的列表,每个运动一个。至少要记住一些事情。
然后你可以简单地在运动员身上使用一个foreach循环,并找到前三个类似的东西:
double minScore = 0;
double maxScore = 0;
double midScore = 0;
foreach(Athlete player in Athletes){
if (player.averageScore >= minScore) {
minScore = midScore;
midScore = maxScore;
maxScore = player.averageScore;
} else if (player.averageScore >= midScore)
minScore = midScore;
midScore = player.averageScore;
} else if (player.averageScore >= minScore);
minScore = player.averageScore;
}
}
虽然上面的代码只能找到所有运动员中的前三个分数,但您可以设置一组独特的分数,然后通过使用类似
的方式过滤掉它们。if(player.GetType() == typeof(Skier))
确定要切换到的集合。如果你经常需要仅根据他们的运动来处理他们,我仍然会建议你将运动员分成运动员,因为它会让一切变得更轻松。
如果将它们拆分为单独的列表,您可以创建一个类似的函数:
private double[] getTopThreeScores(List<Athlete> inAthletes){
//Use this instead of the min/max/mid and then access by the index
double[3] topScores = new double{0.0,0.0,0.0};
/*Loop from above, but switch out topScores[0] for minScore, topScores[1] for mid, etc.*/
return topScores;
}
希望这有点帮助。
保持阵列:
private double[] getTopThreeScores(object inSport, Athlete[] inAthletes){
Type sportType = inSport.GetType();
double[3] topScores = new double{0.0,0.0,0.0};
int length = inAthletes.Length;
for(int i = 0; i < length; i++){
if(inAthletes[i].GetType() == sportType){
if (player.averageScore >= minScore) {
minScore = midScore;
midScore = maxScore;
maxScore = player.averageScore;
} else if (player.averageScore >= midScore)
minScore = midScore;
midScore = player.averageScore;
} else if (player.averageScore >= minScore);
minScore = player.averageScore;
}
}
}
return topScores;
}
会被称为
getTopThreeScores(new Skier(), athletes);
或者你可以传递一名特定的运动员。
不一定是最干净的方式,但它会起作用并允许您指定不同的类型。我没有编译这个,所以可能会有一些小错误。
答案 2 :(得分:0)
你提到:
我希望能够找到数组中每个子类型的前3个averageScores。
所以我提出以下解决方案:
var top3Skiers = athletes.OfType<Skier>()
.OrderByDescending(s => s.AverageScore).Take(3);
与其他解决方案一样,这需要使用System.Linq
命名空间才能工作。 OfType只会选择指定类型的对象,允许您过滤掉您想要的内容。这意味着如果您想要选择前3个IceSkater
,则需要指定OfType<IceSkater>()
。
为了枚举结果,您可以foreach
覆盖它们,如下所示:
foreach (var skier in top3Skiers)
Console.WriteLine("{0} - {1}", skier.Name, skier.AverageScore);