2017-05-19 27 views
-1

如果這是一個重複請讓我知道,我到處搜索..這可能只是一個簡單的LINQ概念,我是不熟悉。LINQ where子句,布爾(孫)在陣列(父)裏面的數組(子)內的過濾器


這是我的數據結構的簡化版本:

public interface ICourse 
{ 
    List<ISession> Sessions { get; set; } 
} 

public interface ISession 
{ 
    Boolean InRange { get; set; } 
} 

問題:我有一個List<ICourse>。我想要返回所有課程(ICourse),但在這些課程上過濾會話(ISession),並且僅包含InRangetrue)的會話。

嘗試:

List<ICourse> results = //data retrieval. 
return results.Where(course => course.Sessions 
       .Where(session => session.InRange).ToList<ISession>()) 
       .ToList<ICourse>(); 

錯誤: 無法隱式轉換類型'System.Collections.Generic.List<ISession>''bool'

無法將lambda表達式轉換爲預期的委託類型,因爲塊中的某些返回類型不會隱式轉換爲委託返回類型。

顯然,這不抱怨時,我只用一個Where條款,即:

return results.Where(course => course.Sessions.Count > 0).ToList<ICourse>(); 

回答

3
results 
    .Where(course => 
    course.Sessions.Where(session => session.InRange).ToList<ISession>() 
) 
    .ToList<ICourse>(); 

Where()是過濾器。它需要一個返回bool的lambda。 Where依次爲枚舉中的每個項目提供lambda表達式,並且lambda期望回答yes或no的問題:「您想將這個東西包含在結果中嗎?」

這裏是你想給這個問題的答案:

course.Sessions.Where(session => session.InRange).ToList<ISession>() 

返回的ISession列表。 Where問你的拉姆達,「你想要這個東西嗎?」而不是「是」或「否」,你的lambda說:「嘿,看看所有這些會話!」在C#中,這不是一個是或否的答案。

編譯器看到這個喜劇程序來到了一英里遠,並且在運行時發生任何愚蠢的事情之前拉動插頭。

所以。

如果您想要返回ICourse的列表,但您希望它們僅包含一小部分開始的會話,則無法創建新的課程對象。既然你在這裏有接口​​,我們不要試圖創建新的對象。無論如何,我懷疑你會想要。

你可以是InRange所有會話的平面列表:

results.SelectMany(c => c.Sessions.Where(s => s.InRange)).ToList(); 

,你可以得到一個元組列表或匿名類型,其對一個ICourse參考用的範圍列表屬於該場會議:

results.Select(c => 
    new Tuple<ICourse, List<ISession>>(
     c, 
     c.Sessions.Where(session => session.InRange).ToList() 
    )) 
.ToList(); 

而且你可以篩選,以排除沒有在範圍內的任何會話課程:

results.Select(c => 
    new Tuple<ICourse, List<ISession>>(
     c, 
     c.Sessions.Where(session => session.InRange).ToList() 
    )) 
.Where(t => t.Item2.Any()) 
.ToList(); 

如果這不僅僅是應用程序某個小角落中的特別事情,我會敦促您編寫一個自定義類來取代Tuple

或者在C#7:

public List<(ICourse Course, List<ISession> Sessions)> 
    GetInRangeSessions(IEnumerable<ICourse> courses) 
    => 
     courses 
     .Select(c => 
      (Course: c, Sessions: c.Sessions.Where(session => session.InRange).ToList()) 
     ) 
     .ToList(); 

只是多了一些刺激性的這種語言是多餘的括號,我們會挖掘小行星。

+1

非常感謝您提供完整,精彩的答案。在你的幫助下,我能夠使我的代碼工作(很好),並擴展了我對LINQ(甚至更好)的理解。 – jhhoff02

0

如果希望所有課程凡Session是INRANGE,我會嘗試...(未測試)

List<ICourse> results = //data retrieval. 
return results.Where(course => course.Sessions.Where(session => session.InRange)).ToList<ISession>()).ToList<ICourse>(); 
+1

你不平衡括號使它很難判斷正是你正在嘗試做的(你有四個開'( '和五個關閉')')。即使除此之外,我不相信任何你放置方括號的地方都可以讓你返回課程,並在那些課程中過濾會話... – Chris

+1

這個錯誤會導致OP得到的錯誤。提交你尚未測試過的「敏捷」答案是可以的,但是你回去測試一下。 –

1

我認爲最簡單的想法就是寫:

List<Sessions> temporary = new List<Sessions>(); 

     foreach (Course s in courses) 
     { 
      temporary = s.sessions.Where(x => x.InRange == true).ToList(); 
      s.sessions = temporary; 
      temporary.Clear(); 
     } 
2

埃德賓吉的答案是正確的,但我要問,爲什麼你要一個新的ICourse對象名單。爲什麼不直接使用全ICourse名單,只是過濾,他們正在使用的會話:

foreach(var c in Courses) 
{ 
     foreach(var s in c.Sessions.Where(session => session.InRange)) 
     {.... } 
}