Created
August 25, 2016 02:58
-
-
Save VienosNotes/c9769242dafae1968f7cf403fd8083cd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace MyLinq | |
{ | |
/// <summary> | |
/// LINQ拡張メソッドを定義するためのユーティリティクラスです。 | |
/// </summary> | |
public static class LinqEx | |
{ | |
/// <summary> | |
/// コレクションの要素を先頭から順にN個ずつとりだした部分列に分割します(SelectManyの逆操作)。要素数がNの倍数でない場合はdefault(TSource)で補填されます。 | |
/// </summary> | |
/// <typeparam name="TSource">ソースコレクションの要素の型。</typeparam> | |
/// <param name="source">ソースコレクション。</param> | |
/// <param name="takeCount">一度に何個ずつ取り出すか。省略した場合は既定値2が使用されます。</param> | |
/// <param name="padding"></param> | |
/// <returns>もとの要素がN個ずつに分割されたコレクションのコレクション。</returns> | |
public static IEnumerable<IEnumerable<TSource>> ZipSelf<TSource>(this IEnumerable<TSource> source, int takeCount = 2, bool padding = true) | |
{ | |
if (takeCount < 1) | |
{ | |
throw new ArgumentOutOfRangeException("takeCount は1以上の整数である必要があります。"); | |
} | |
return ZipSelfIterator<TSource>(source, takeCount, padding); | |
} | |
/// <summary> | |
/// ZipSelfの実装。 | |
/// </summary> | |
/// <typeparam name="TSource">ソースコレクションの要素の型。</typeparam> | |
/// <param name="source">ソースコレクション。</param> | |
/// <param name="takeCount">一度に何個ずつ取り出すか。省略した場合は既定値2が使用されます。</param> | |
/// <param name="padding"></param> | |
/// <returns>もとの要素がN個ずつに分割されたコレクションのコレクション。</returns> | |
private static IEnumerable<IEnumerable<TSource>> ZipSelfIterator<TSource>(this IEnumerable<TSource> source, int takeCount, bool padding) | |
{ | |
IEnumerator<TSource> en = source.GetEnumerator(); | |
while (en.MoveNext()) | |
{ | |
var curList = new List<TSource>(); | |
curList.Add(en.Current); | |
for (var i = 0; i < takeCount - 1; i++) | |
{ | |
if (en.MoveNext()) | |
{ | |
curList.Add(en.Current); | |
} | |
else | |
{ | |
if (padding) | |
{ | |
curList.Add(default(TSource)); | |
} | |
} | |
} | |
yield return curList; | |
} | |
} | |
/// <summary> | |
/// 複数のシーケンスから要素を1つずつ取り出して、それらにセレクタを適用したシーケンスを返します。 | |
/// Enumerable.Zip() との違いは、各入力シーケンスの長さが一致しない場合に短いシーケンスの不足要素が default(TSource) で補填された状態でセレクタを適用する点です。 | |
/// </summary> | |
/// <typeparam name="TSource">入力シーケンスの要素の型。</typeparam> | |
/// <typeparam name="TResult">セレクタによって射影された型。</typeparam> | |
/// <param name="selector">入力シーケンスの要素を受け取って射影するセレクタ。このセレクタは default(TSource) を引数の要素として受け取ることを想定する必要があります。</param> | |
/// <param name="sources">入力シーケンスの列。</param> | |
/// <returns>射影されたシーケンス。このシーケンスの要素数は、入力シーケンスの中で一番要素数が多いものの要素数と一致します。</returns> | |
public static IEnumerable<TResult> MultipleZip<TSource, TResult>(Func<IEnumerable<TSource>, TResult> selector, params IEnumerable<TSource>[] sources) | |
{ | |
if (sources == null || sources.Length == 0) | |
{ | |
return new List<TResult>(); | |
} | |
if (selector == null) | |
{ | |
throw new ArgumentException("selectorはnullを許容しません。"); | |
} | |
return MultipleZipIterator(selector, sources); | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <typeparam name="TSource"></typeparam> | |
/// <typeparam name="TResult"></typeparam> | |
/// <param name="selector"></param> | |
/// <param name="sources"></param> | |
/// <returns></returns> | |
private static IEnumerable<TResult> MultipleZipIterator<TSource, TResult>(Func<IEnumerable<TSource>, TResult> selector, params IEnumerable<TSource>[] sources) | |
{ | |
var idx = 0; | |
var ss = sources.Select(s => s.ToList()); | |
while (true) | |
{ | |
var list = new List<TSource>(); | |
foreach (var s in ss) | |
{ | |
if (idx < s.Count) | |
{ | |
list.Add(s[idx]); | |
} | |
else | |
{ | |
list.Add(default(TSource)); | |
} | |
} | |
if (list.All(item => item.Equals(default(TSource)))) | |
{ | |
yield break; | |
} | |
else | |
{ | |
yield return selector(list); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment