2011-08-09 76 views
0

考慮下面的IEnumerable(串):如何根據模式按T的順序對IEnumerable(Of T)進行分區?

Moe1 
    Larry1 
    Curly1 
    Shemp1 
    Curly1 

    Moe2 
    Larry1 
    Curly1 
    Shemp1 
    Curly1 
    Curly2 
    Shemp2 
    Curly1 
    Curly2 

    Larry2 
    Curly1 

    Larry3 
    Shemp1 

他們在視覺上分裂這裏,使圖案更容易看到。我想用.StartsWith()謂詞來劃分一個IEnumerable(串),爲一個IEnumerable(中IEnumerable的(串)

的規則是:

  • 每一個分區的子集必須有一個拉里,並威力有莫伊
  • 分區上遇到
  • 如果拉里緊跟,把他與上次
  • 如果拉里緊跟別人,分區上拉里
  • 所有其他走狗放在當前分區
  • Moe以外Larger可以在分區中重複

我使用.StartsWith(「萌」)等,以確定傀儡的類型,但我有一個很難搞清楚如何這套使用LINQ運營商分區,以便如果Moe存在時,他代表分區的頭部,但由於Larry必須存在於每個分區中,因此他可能代表分區的頭部,前提是Moe不在他之前。

如何創建了IEnumerable(中IEnumerable的(串),這樣的結果是分區的方式,我展示了一組與空行?

如果沒有合適的LINQ運營商,因爲我是這樣的(在VB.NET中編程,如果VB.NET & C#之間的功能存在細微的差異),我只需編寫一個方法來做到這一點,我可以做到這一點,但我認爲這可能是一個問題出現並事先與LINQ運營商迎刃而解。

感謝。

+4

這看起來像一個小的狀態機,它可能更容易使用的標準做循環和手動創建各個子集合 - Linq不會讓這個更容易。 – BrokenGlass

回答

2

LINQ做這似乎不是一個解決方案,因爲你有非常複雜的分裂條件,你想要產生的數據結構並不是典型的LINQ查詢。 AFAIK,旨在一次知道序列中多個元素的唯一LINQ操作符是Aggregate,但它不適合這裏,因爲我們正在做與聚合相反的事情。

所以你的問題似乎解決了容易使用經典的循環,更不像是(不徹底的測試):

public IEnumerable<IEnumerable<string>> Partition(IEnumerable<string> input) 
{ 
    var currPartition = new List<string>(); 
    string prev = null; 

    foreach (var elem in input) 
    { 
     if (ShouldPartition(prev, elem)) 
     { 
      yield return currPartition; 
      currPartition = new List<string>(); 
     } 

     currPartition.Add(elem); 
     prev = elem; 
    } 

    yield return currPartition; 
} 

private bool ShouldPartition(string prev, string elem) 
{ 
    if (prev == null) 
     return false; 
    if (elem.StartsWith("Moe")) 
     return true; 
    if (elem.StartsWith("Larry")) 
     return !prev.StartsWith("Moe"); 
    return false; 
} 
+0

非常感謝這個乾淨的例子 - 我認爲這是我最終選擇的路線。 – Jeff

相關問題