2011-12-01 70 views
1

我有一個類,看起來像這樣:LAMBDA至少存在的元素

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

我收到了這些對象的列表,我想通過FormId獲得由SubjectId最少發生的一個即可。我也想回到第一個整個元素。不只是財產。

這裏是我的嘗試:

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

但這僅返回SubjectId。我想要整個教師對象並且還要添加第二排序條件FormId

+1

因此,最少出現SubjectId的最少出現FormId的第一項?那是對的嗎?因此,確定SubjectId的最小計數,並在該組內確定FormId的最小計數,然後在該組內採取第一項? –

+0

@AnthonyPegram是的。 –

+0

而不是'Select(g => g.Key)'try'SelectMany(g => g)'。 (如果這是正確的,我現在太累了想現在; p) – leppie

回答

2

你很近。你需要Lookup的第一項(你有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有至少一個元素,代表誰教至少成才的主題與最少使用的形式老師(一個或多個)。

瞭解系統中可能存在根本未教授的科目。他們在這裏不會有代表,因爲沒有老師教這個班。查詢只會考慮至少有一位教師的科目。

編輯:重讀你的問題後,我想我明白髮生了什麼事。這些「授課科目」涉及教授某一特定「形式」或「年級」(美國系統的一年級至十二年級)的特定科目(數學,閱讀,科學,藝術,音樂)。

由於您目前設置了對象,所以可能會有相同主題和等級的重複條目,但除了TaughtSubjectID字段(可能只是從計數器或標識分配)之外,它們是無法區分的。

無論你想如何完成,也可以將教師包含在TaughtSubject中,這樣會更有意義。舉例來說,這可以讓你列出教授那門課最少教的科目的教師,或者按照大衛B的說法,教授學科和等級最低的整體組合。

你想要哪一個是主觀的,並且存在語義差異。音樂可能是最少教的科目(只提供給9-12年級的學生),但是每個年級都有兩到三位老師教授音樂。另一方面,數學可以在每個年級水平上教授,教師總數很多,因此與音樂相比,具有更多的TaughtSubject記錄,但是整個組中可能只有一名6年級的數學老師。找到最少教的科目最少教的成績會給你9年級的音樂。找到最少的教學整體學科組合會給你6年級的數學。

+0

+1對於tiebreaking –

+0

,我無法再爲您提供另一個+1編輯。 –

+0

老師已經包含在模型中,我只是將它排除在SO目的之外。我會添加它 –

-1

我建議你不要試圖在單個表達式中做到這一點。讀者很難理解正在發生的事情。把它分成兩個表達式,一個用於formid的subjectid。

+1

這不是他的問題的答案......將其作爲評論或提出答案。 –

0

你可以使用排序依據和ThenBy:

輸出:

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 
+0

那麼分組呢? – leppie

+1

@leppie:爲什麼分組?他需要結果[0] – BlackBear

+0

「最少出現的元素」,但可以有多於一個元素符合條件。 – leppie

0
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 

,如果你願意,你可以添加其他條件類似。

+0

哎唷,這個'let'會執行太多次 – leppie

+1

或者你可以隨時把它放在外面,如果你想。 –

+0

這會工作,但我認爲OP需要'特殊'單個表達式:) – leppie

1

這是第二組,而不是第二次排序條件:

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(); 
相關問題