简体   繁体   English

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

[英]Grouping, adding up then sorting with linq

I have 3 tables Drivers, Races and DriverRaces. 我有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; }
}

There are 5 classes of races, a driver can be in more than one class, and can compete in multiple races. 共有5个类别的比赛,一个驾驶员可以参加多个类别的比赛,并且可以参加多个比赛。 I am trying to write a linq statement to get the top 5 drivers of each class, and the sum of their total points from each race in that class. 我正在尝试编写linq语句,以获取每个类别的前5名车手以及该类别中每个种族的总积分。

I know how to select all rookie drivers and get their names and points 我知道如何选择所有新秀司机并获取他们的姓名和积分

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

Which could return something like 这可能会返回类似

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

But I want it to show 但我要显示

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

I need help adding up each drivers totals and then sorting them. 我需要帮助将每个驱动程序的总计加起来,然后对它们进行排序。

To achieve the goal you will need to aggregate these results. 为了实现该目标,您将需要汇总这些结果。 There are two approaches one uses Aggregate other Select . 一种方法是使用Aggregate另一种是Select Aggregate is more performant while Select is cleaner. Aggregate Select更干净时, Aggregate的性能更高。

I've added a small example to indicate behavior: 我添加了一个小示例来指示行为:

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

EDIT: 编辑:

Another approach could be to use Aggregate function not as pretty but more performant: 另一种方法可能是使用Aggregate函数不那么漂亮,但性能更高:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM