分组,加起来然后用linq排序

Grouping, adding up then sorting with linq

我有 3 个表 Drivers、Races 和 DriverRaces。

public partial class Driver
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Driver()
    {
        this.DriverRaces = new HashSet<DriverRace>();
    }

    public int DriverID { get; set; }

    [DisplayName("Name")]
    public string DriverName { get; set; }

    [DisplayName("Number")]
    public string DriverNumber { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<DriverRace> DriverRaces { get; set; }
}

public partial class DriverRace
{
    public int DriverRaceID { get; set; }

    public int Points { get; set; }

    [DisplayName("Driver")]
    public Nullable<int> Driver_DriverID { get; set; }

    [DisplayName("Race")]
    public Nullable<int> Race_RaceID { get; set; }

    public virtual Driver Driver { get; set; }

    public virtual Race Race { get; set; }
}

public partial class Race
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Race()
    {
        this.DriverRaces = new HashSet<DriverRace>();
    }
    public int RaceID { get; set; }

    public System.DateTime RaceDate { get; set; }

    [DisplayName("Name")]
    public string RaceName { get; set; }

    [DisplayName("Class")]
    public string RaceClass { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<DriverRace> DriverRaces { get; set; }
}

有5个class种族,一个driver可以在多个class,可以参加多个种族。我正在尝试编写一个 linq 语句来获得每个 class 的前 5 driver,以及他们在 class.

中每场比赛的总分之和

我知道如何 select 所有新手 driver 并获得他们的名字和分数

var drivers = DriverRaces.Where(d=>d.Points > 0 && d.Race.RaceClass == "Rookie");
foreach (var driver in drivers){
    Console.WriteLine("Driver Name is {0} points is {1}", driver.Driver.DriverName, driver.Points);
}

哪个可以return类似

Driver Name is Alexander points is 100
Driver Name is Mady points is 99
Driver Name is Blake points is 98
Driver Name is Alexander points is 100
Driver Name is Mady points is 99
Driver Name is Tom points is 98

但我想让它显示

Driver Name is Alexander points is 200
Driver Name is Mady points is 198
Driver Name is Blake points is 98
Driver Name is Tom points is 98

我需要帮助将每个 driver 的总数相加,然后对它们进行排序。

要实现目标,您需要汇总这些结果。有两种方法,一种使用 Aggregate,另一种使用 SelectAggregate 性能更高,而 Select 更干净。

我添加了一个小示例来说明行为:

class Program
{
    static void Main(string[] args)
    {
        List<Driver> driversFirstTable = new List<Driver>()
        {
            new Driver
            {
                DriverName = "John", DriverRaces = new Collection<DriverRace>
                {
                    new DriverRace { Points = 99, Category = "Rookie" },
                    new DriverRace { Points = 100, Category = "Rookie" },
                    new DriverRace { Points = 10, Category = "Mid" },
                    new DriverRace { Points = 99, Category = "Pro" },
                }
            },

            new Driver
            {
                DriverName = "Jack", DriverRaces = new Collection<DriverRace>
                {
                    new DriverRace { Points = 100, Category = "Rookie" },
                    new DriverRace { Points = 98, Category = "Rookie" },
                    new DriverRace { Points = 66, Category = "Mid" },
                    new DriverRace { Points = 100, Category = "Pro" },
                }
            },
            new Driver
            {
                DriverName = "Richard", DriverRaces = new Collection<DriverRace>
                {
                    new DriverRace { Points = 98, Category = "Rookie" },
                    new DriverRace { Points = 99, Category = "Rookie" },
                    new DriverRace { Points = 62, Category = "Mid" },
                    new DriverRace { Points = 98, Category = "Pro" },
                }
            },
            new Driver
            {
                DriverName = "Will", DriverRaces = new Collection<DriverRace>
                {
                    new DriverRace { Points = 97, Category = "Rookie" },
                    new DriverRace { Points = 97, Category = "Rookie" },
                    new DriverRace { Points = 61, Category = "Mid" },
                    new DriverRace { Points = 97, Category = "Pro" },
                }
            }
        };


        var rookieTop = driversFirstTable
            .Select(x => new DriverAggregated { Category = "Rookie", DriverName = x.DriverName, TotalPoints = x.DriverRaces.Where(y => y.Category == "Rookie").Sum(y => y.Points) })
            .OrderByDescending(x => x.TotalPoints)
            .Take(3);
        // Will is not in the list
        foreach (var driver in rookieTop)
        {
            Console.WriteLine($"Driver - {driver.DriverName} gathered {driver.TotalPoints} points.");
        }
        Console.Read();
    }
}

class DriverAggregated
{
    public string DriverName { get; set; }
    public int TotalPoints { get; set; }
    public string Category { get; set; }
}

public class Driver
{
    public string DriverName { get; set; }

    public virtual ICollection<DriverRace> DriverRaces { get; set; }
}

public class DriverRace
{
    public int Points { get; set; }
    public string Category { get; set; }
}

编辑:

另一种方法可能是使用聚合函数,虽然不那么漂亮但性能更高:

        var topRookie = driversFirstTable.Select(x => x.DriverRaces.Aggregate(new DriverAggregated() { Category = "Rookie", DriverName = x.DriverName }, (seed, race) =>
          {
              if (race.Category == seed.Category)
                  seed.TotalPoints += race.Points;
              return seed;
          }))
         .OrderByDescending(x => x.TotalPoints)
         .Take(3);