I wrote a LINQ extension method SplitBetween
analogous to String.Split
.
> new List(){3,4,2,21,3,2,17,16,1}
> .SplitBet
This one won't use List<>
, and won't go BOOM.
public static IEnumerable> SplitBetween(this IEnumerable source,
Func separatorSelector,
bool includeSeparators=false)
{
if (source == null)
throw new ArgumentNullException("source");
return SplitBetweenImpl(source, separatorSelector, includeSeparators);
}
private static IEnumerable SplitBetweenInner(IEnumerator e,
Func separatorSelector)
{
var first = true;
while(first || e.MoveNext())
{
if (separatorSelector((T)e.Current))
yield break;
first = false;
yield return e.Current;
}
}
private static IEnumerable> SplitBetweenImpl(this IEnumerable source,
Func separatorSelector,
bool includeSeparators)
{
using (var e = source.GetEnumerator())
while(e.MoveNext())
{
if (separatorSelector((T)e.Current) && includeSeparators)
yield return new T[] {(T)e.Current};
else
{
yield return SplitBetweenInner(e, separatorSelector);
if (separatorSelector((T)e.Current) && includeSeparators)
yield return new T[] {(T)e.Current};
}
}
}
Test:
void Main()
{
var list = new List(){1, 2, 3, 10, 1};
foreach(var col in list.Concat(Ext.ThrowingEnumerable())
.SplitBetween(x=>x>=10).Take(1))
{
Console.WriteLine("------");
foreach(var i in col)
Console.WriteLine(i);
}
}
Output:
------
1
2
3
Test2
var list = new List(){1, 2, 3, 10, 1}
foreach(var col in list.Concat(Ext.ThrowingEnumerable())
.SplitBetween(x=>x>=10).Take(2))
Output:
------
1
2
3
------
1
*Exception*
Here, the exception is caused because the first element of the ThrowingEnumerable
-enumeration would go into the same group as the 1
.
Test3:
var list = new List(){1, 2, 3, 10, 1, 17};
foreach(var col in list.Concat(Ext.ThrowingEnumerable())
.SplitBetween(x=>x>=10, true).Take(4))
Output:
------
1
2
3
------
10
------
1
------
17
No problem here, because the Exception element would go into it's own group, and thus is not iterated over due to Take(4)
: