Lambda元素最少

本文关键字:元素 Lambda | 更新日期: 2023-09-27 18:16:29

我有一个类看起来像这样:

public class TaughtSubject
{
    public int TaughtSubjectId { get; set; }
    public int TeacherId { get; set; }
    public Teacher Teacher { get; set; }
    public int FormId { get; set; }
    public Form FormId { get; set; }
    public int SubjectId { get; set; }
    public Subject Subject { get; set; }
}

我收到了这些对象的列表,我想通过SubjectId然后通过FormId获得出现次数最少的对象。我还想取回第一个整个元素。不仅仅是房产。

这是我的尝试:

var teacher = taughtSubjects.GroupBy(t => t.SubjectId).OrderBy(g => g.Count()).Select(g => g.Key).First();

但这只返回SubjectId。我想要整个教师对象,并且还添加第二排序条件FormId

Lambda元素最少

你很接近。您需要查找的第一项(GroupBy的结果(,然后在查找元素的值中,您要按FormId进行分组,并返回其中出现次数最少的教师。

var teachers = taughtSubjects
   .GroupBy(ts => ts.SubjectId)
   .OrderBy(g => g.Count())
   .ThenBy(g=>g.Key) //tiebreaker
   .First() //gets the IEnumerable of Teachers that teach this least-taught subject
   .GroupBy(t=>t.FormId)
   .OrderBy(g=>g.Count())
   .ThenBy(g=>g.Key) //as a tiebreaker
   .First() //gets the teacher(s) with the lowest specified FormId.

这将返回一个至少有一个元素的教师IEnumerable,代表用最少使用的形式教授最少教学科目的教师。

要明白,你的系统中可能有一些科目根本没有教过。他们不会在这里被代表,因为没有老师教这个班。该查询将只考虑至少有一名教师的科目。

编辑:重读你的问题后,我想我明白发生了什么。这些"教授的科目"与按照特定"形式"或"年级水平"(美国系统为一年级至十二年级(教授的特定科目(数学、阅读、科学、艺术、音乐(有关。

由于您目前已经设置了对象,相同科目和年级的重复条目是可能的,但除了TaughSubjectID字段(可能只是从计数器或身份分配的(之外,它们将无法区分。

无论你想怎么做,把老师也包括在教学科目中都会更有意义。例如,这将允许你列出在该科目的教学最少年级中教授教学最少科目的教师,或者如大卫·B所建议的,列出科目和年级的整体组合中教授最少科目的老师。

你想要哪一个是主观的,并且存在语义差异。音乐可能是教得最少的科目(只提供给9-12年级的学生(,但每个年级都有两三名老师在教。另一方面,数学可能在每个年级都有大量教师教授,因此其科目记录的数量高于音乐,但整个小组中可能只有一名六年级的数学教师。找到教授最少的科目中教授最少的一个年级,你就能上九年级的音乐课。找到教得最少的科目-年级组合会给你六年级的数学成绩。

这是第二个分组,而不是第二个排序条件:

IEnumerable<TaughtSubject> firstGroup = taughtSubjects
  .GroupBy(t => t.SubjectId)
  .OrderBy(g => g.Count())
  .First()  //the taughtsubjects that are members of the smallest subject group.
  .GroupBy(t => t.FormId)
  .OrderBy(g => g.Count())
  .First(); // and of these taughtsubjects, the members of the smallest form group.
  // and the first member of those.
TaughtSubject firstElement = firstGroup.First();

以上是你的要求,但大多数人都希望在给定的形式和主题配对中选择最小的小组。就是这样做的。

IEnumerable<TaughtSubject> firstGroup = taughtSubjects
  .GroupBy(t => new {t.FormId, t.SubjectId})
  .OrderBy(g => g.Count())
  .First();
  // and the first member of those.
TaughtSubject firstElement = firstGroup.First();
var result = from ts in TaughtSubjects
let leastSubjId = taughtSubjects.GroupBy(t => t.SubjectId).OrderBy(g => g.Count()).Select(g => g.Key).First()
where ts.SubjectId == leastSubjId
select ts

如果你愿意,你可以添加另一个类似的条件。

您只需使用OrderBy和ThenBy:

public class foo
{
    public int e1 { get; set; }
    public int e2 { get; set; }
    public int e3 { get; set; }
    public int e4 { get; set; }
    public foo(int e1, int e2, int e3, int e4)
    {
        this.e1 = e1;
        this.e2 = e2;
        this.e3 = e3;
        this.e4 = e4;
    }
    public override string ToString()
    {
        return string.Format("e1 = {0}'te2 = {1}'te3 = {2}'te4 = {3}",
            e1, e2, e3, e4);
    }
}
public static void Main(string[] args)
{
    List<foo> foosList = new List<foo>();
    Random r = new Random((int)DateTime.Now.Ticks);
    for (int i = 0; i < 15; i++)
        foosList.Add(new foo(r.Next(20), r.Next(20), r.Next(10), r.Next(5)));
    List<foo> result = foosList.OrderBy(e => e.e4).ThenBy(e => e.e3).ToList();
    result.ForEach(e => Console.WriteLine(e));
    Console.ReadKey();
}

输出:

e1 = 7  e2 = 4  e3 = 2  e4 = 0
e1 = 18 e2 = 12 e3 = 4  e4 = 0
e1 = 9  e2 = 8  e3 = 6  e4 = 0
e1 = 6  e2 = 8  e3 = 6  e4 = 0
e1 = 13 e2 = 14 e3 = 8  e4 = 0
e1 = 6  e2 = 15 e3 = 1  e4 = 2
e1 = 18 e2 = 10 e3 = 1  e4 = 2
e1 = 14 e2 = 3  e3 = 8  e4 = 2
e1 = 7  e2 = 3  e3 = 3  e4 = 3
e1 = 11 e2 = 6  e3 = 4  e4 = 3
e1 = 11 e2 = 17 e3 = 1  e4 = 4
e1 = 16 e2 = 1  e3 = 2  e4 = 4
e1 = 16 e2 = 11 e3 = 7  e4 = 4
e1 = 12 e2 = 5  e3 = 8  e4 = 4
e1 = 7  e2 = 7  e3 = 9  e4 = 4

我建议您不要尝试在单个表达式中执行此操作。读者很难理解发生了什么。把它分成两个表达,一个表示主语,另一个表示形式。

相关文章: