読者です 読者をやめる 読者になる 読者になる

Kokudoriing

技術系与太話ブログ

条件式判断でリストを分割する拡張メソッド

何を言ってるのかわからないかもしれませんが、いわゆる文字列のSplitのリスト版というかIEnumerable<T>版というかが欲しい。

var nums = new { 1, 2, -1, 5, 6, 8, -1, 11, 2, 4, 6, -1, 9 };

// -1を区切り数としてリストを分割したい.
// {{1, 2}, {5, 6, 8}, {11, 2, 4, 6}, 9} になってほしい.

リスト分割はIx(Interactive Extensions)でBuffer拡張メソッドがあります。
ただ、これは任意個ごとに分割したIEnumerable<T>を返すんですよねー。

var nums = new { 1, 2, -1, 5, 6, 8, -1, 11, 2, 4, 6, -1, 9 };

nums.Buffer(3).ForEach(x => Console.WriteLine(string.Join(",\t", x)));
// 1,      2,      -1
// 5,      6,      8
// -1,     11,     2
// 4,      6,      -1
// 9

んー、確かに便利なんですが、Func<T, bool>を受け取っていただきたく・・。
というわけで作ってみました。

https://gist.github.com/kokudori/5314509

using System;
using System.Collections.Generic;
using System.Linq;

static class Extentions
{
  public static IEnumerable<IEnumerable<T>> Buffer<T>(this IEnumerable<T> source, Func<T, bool> func)
  {
    while (source.Any())
    {
      yield return source.TakeWhile(x => !func(x));
      source = source.SkipWhile(x => !func(x)).Skip(1);
    }
  }
}

class Program
{
  static void Main(string[] args)
  {
    var nums = new[] { 1, 2, -1, 5, 6, 8, -1, 11, 2, 4, 6, -1, 9 };

    nums.Buffer(x => x == -1).ForEach(x => Console.WriteLine(string.Join(",\t", x)));
  }
}

// output:
// 1,      2
// 5,      6,      8
// 11,     2,      4,      6
// 9

これなんでIxに入ってないんだろ。
もしかして車輪の再発明しちゃってる・・?