Scala の sliding メソッドを作成してみる
Scala には、sliding
メソッドというのがあります。これを C# で実装してみました。
using System; using System.Collections.Generic; using System.Linq; static class Ext { public static IEnumerable<T[]> Sliding<T>(this IEnumerable<T> src, int size, int step=1) { var xs = new List<T>(); int index = 0; int headIndex = 0; bool added = false; foreach (var e in src) { if (index >= headIndex) { xs.Add(e); added = true; if (xs.Count == size) { yield return xs.ToArray(); added = false; headIndex += step; xs = xs.Skip(step).ToList(); } } index++; } if (xs.Count > 0 && added) yield return xs.ToArray(); } } class Program { // 出力確認用 static void Display<T>(IEnumerable<T[]> xs) { var ls = xs.Select(e => "[" + string.Join(",", e) + "]"); Console.WriteLine("[" + string.Join(",", ls) + "]"); } static void Main() { var xs = new[] { 1, 2, 3, 4, 5 }; for (int i = 1; i <= xs.Length; i++) { Display(xs.Sliding(i)); } Console.WriteLine("2 個ずつにする:"); Display(xs.Sliding(2, 2)); } }
実行結果です。
[[1],[2],[3],[4],[5]] [[1,2],[2,3],[3,4],[4,5]] [[1,2,3],[2,3,4],[3,4,5]] [[1,2,3,4],[2,3,4,5]] [[1,2,3,4,5]] 2 個ずつにする: [[1,2],[3,4],[5]]
Sliding
メソッドがあると、階差数列を求めたり、要素を N 個ごとにグルーピングするのが簡単にできるようになります。
階差数列を求める
var xs = new[] { 1, 6, 15, 28, 45, 66 }; var ys = xs.Sliding(2).Select(e => e[1] - e[0]); Console.WriteLine(string.Join(", ", ys));
隣り合う要素の差を求めています。
実行結果:
5, 9, 13, 17, 21
連続する重複要素をひとつにまとめる
static int[] Compact(int[] xs) { if (xs.Length <= 1) return xs; return xs.Take(1).Concat(xs.Sliding(2).Where(e => e[0] != e[1]).Select(e => e[1])).ToArray(); } // 連続している重複要素をひとつにする var xs = new[] { 1, 1, 2, 3, 3, 3, 4, 2, 2, 5 }; var a = Compact(xs); Console.WriteLine(string.Join(", ", a));
Compact メソッドでは、隣り合う要素が違いに異なるもののみを Where
で取り出して、Select
で 2 番目の要素を取り出しています。こうすると連続する重複要素を取り除くことが出来ます。
実行結果:
1, 2, 3, 4, 2, 5
要素を N 個ごとにグループ化する
var xs = Enumerable.Range(0, 10); // 3 個ごとにグループ化する Display(xs.Sliding(3, 3));
実行結果:
[[0,1,2],[3,4,5],[6,7,8],[9]]