Reputation: 2271
Consider the following IEnumerable(Of String):
Moe1
Larry1
Curly1
Shemp1
Curly1
Moe2
Larry1
Curly1
Shemp1
Curly1
Curly2
Shemp2
Curly1
Curly2
Larry2
Curly1
Larry3
Shemp1
They're visually split here to make the pattern easier to see. I want to partition an IEnumerable(Of String) using the .StartsWith() predicate, into an IEnumerable(Of IEnumerable(Of String).
The rules are:
I'm using the .StartsWith("Moe"), etc. to identify the type of stooge, but I'm having a hard time figuring out how to partition this set using LINQ operators so that if Moe is present, he represents the head of a partition, but since Larry must exist in each partition, he might represent the head of a partition if a Moe does not precede him.
How can I create the IEnumerable(Of IEnumerable(Of String) so that the result is partitioned the way I display the set with blank lines?
If there are no suitable LINQ operators for something like this (I'm programming in VB.NET if there are subtle differences in capabilities between VB.NET & C#), and I simply need to write a method to do this, I can do that, but I thought this might be a problem that comes up and is solved easily with LINQ operators.
Thanks in advance.
Upvotes: 0
Views: 306
Reputation: 9672
LINQ doesn't seem to be a solution here as you have pretty complex split condition and the data structure you want to produce is not typical for LINQ queries. AFAIK, the only LINQ operator that is intended to know more than one element of the sequence at once is Aggregate
, but it doesn't fit here as we're doing something inverse from aggregating.
So your problem seems to be solved easier using classical loops, more less like that (not tested thoroughly):
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;
}
Upvotes: 2