如何根据T的顺序基于模式对IEnumerable(Of T)进行分区?

时间:2011-08-09 18:37:26

标签: linq ienumerable subset

考虑以下IEnumerable(Of String):

    Moe1
    Larry1
    Curly1
    Shemp1
    Curly1

    Moe2
    Larry1
    Curly1
    Shemp1
    Curly1
    Curly2
    Shemp2
    Curly1
    Curly2

    Larry2
    Curly1

    Larry3
    Shemp1

它们在视觉上分开,使图案更容易看到。我想使用.StartsWith()谓词将IEnumerable(Of String)分区为IEnumerable(Of IEnumerable(Of String)。

规则是:

  • 每个分区子集必须具有 Larry 可能拥有Moe
  • Moe 遇到时
  • 分区 Moe
  • 如果 Larry 紧跟 Moe ,请将他与最后 Moe
  • 放在一起
  • 如果 Larry 紧跟其他人, Larry 上的分区
  • 所有其他傀儡都放在当前分区
  • Moe 以及 Larry 以外的所有傀儡都可以在分区中重复

我正在使用.StartsWith(“Moe”)等来识别stooge的类型,但是我很难弄清楚如何使用LINQ运算符对这个集进行分区,以便 if < / em> Moe 存在,他代表分区的负责人,但由于 Larry 必须存在于每个分区中,如果 Moe 不在他之前。

如何创建IEnumerable(IEnumerable(Of String)),以便按照我用空行显示集合的方式对结果进行分区?

如果没有合适的LINQ运算符(我在VB.NET中编程,如果VB.NET和C#之间的功能存在细微差别),我只需编写一个方法来执行此操作我可以这样做,但我认为这可能是一个问题,并且可以通过LINQ运营商轻松解决。

提前致谢。

1 个答案:

答案 0 :(得分: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;
}