SplitBetween
に類似した LINQ 拡張メソッドを作成しましたString.Split
。
> new List<int>(){3,4,2,21,3,2,17,16,1}
> .SplitBetween(x=>x>=10)
[3,4,2], [3,2], [], [1]
ソース:
// partition sequence into sequence of contiguous subsequences
// behaves like String.Split
public static IEnumerable<IEnumerable<T>> SplitBetween<T>(this IEnumerable<T> source,
Func<T, bool> separatorSelector,
bool includeSeparator = false)
{
var l = new List<T>();
foreach (var x in source)
{
if (separatorSelector(x))
{
if (includeSeparator)
{
l.Add(x);
}
yield return l;
l = new List<T>();
}
else
{
l.Add(x);
}
}
yield return l;
}
LINQ の精神では、このメソッドは遅延評価を行うべきだと思います。ただし、私の実装では、外側の IEnumerable に対して遅延評価を行いますが、内側の IEnumerable に対しては行いません。どうすればこれを修正できますか?
外側の動作がいかに怠惰であるかのデモンストレーション。AssumeThrowingEnumerable<int>
は、IEnumerable<int>
誰かが反復しようとすると爆発する です (Skeet の Edulinq を参照してください)。
(new List<int>(){1,2,3,10,1})
.Concat(Extensions.ThrowingEnumerable<int>())
.SplitBetween(x=>x>=10)
.First().ToList();
[1,2,3]
しかし、内面の振る舞いは怠け者ではありません
(new List<int>(){1,2,3,10,1})
.Concat(Extensions.ThrowingEnumerable<int>())
.SplitBetween(x=>x>=10)
.ElementAt(2).First();
BOOM
ここでは 1 を期待します。