次の関数は、3 つのコレクションに対して実行される Zip 関数のテスト済みバージョンです。一度にすべての結果を計算するわけではありませんが、Linq の Zip 関数と同様に遅延実行を使用します。
static class ThreeWayZip
{
public static IEnumerable<TResult> Zip3<TFirst, TSecond, TThird, TResult>(
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
IEnumerable<TThird> third,
Func<TFirst, TSecond, TThird, TResult> resultSelector)
{
if(first == null || second == null || third == null)
{ throw new ArgumentNullException(); }
using (var iterator1 = first.GetEnumerator())
using (var iterator2 = second.GetEnumerator())
using (var iterator3 = third.GetEnumerator())
{
while(iterator1.MoveNext()
&& iterator2.MoveNext()
&& iterator3.MoveNext())
{
yield return resultSelector(
iterator1.Current, iterator2.Current, iterator3.Current);
}
}
}
}
私が実行したテストは次のとおりです。
int Min3(int x, int y, int z)
{
if(x<=y)
{
if(x<=z)
{ //x<=z && x<=y
return x;
}
//z<x && x<=y
return z;
}
//y<x
if(z<=y) return z;
//y<z && y<x
return y;
}
[TestMethod]
public void Test_Zip3()
{
int[] a = { 2, 3, 5 };
int[] b = { 3, 2, 5 };
int[] c = { 5, 1, 5 };
IEnumerable<int> result = a.Zip3(b, c, Min3);
CollectionAssert.AreEqual(new[] {2, 1, 5}, result.ToArray());
}
[TestMethod]
public void Zip_With_Different_ArrayLength()
{
int[] a = { 2, 3, };
int[] b = { 3, 2, 5 };
int[] c = { 5, 1, 5, 8 };
var result = a.Zip3(b, c, Min3);
CollectionAssert.AreEqual(new[] {2, 1}, result.ToArray());
}
[TestMethod]
public void Zip_With_EmptyArray()
{
int[] a = { 2, 3, };
int[] b = { 3, 2, 5 };
int[] c = { };
var result = a.Zip3(b, c, Min3);
CollectionAssert.AreEqual(new int[0], result.ToArray());
}
[TestMethod]
public void Zip_With_First_ArrayEmpty()
{
int[] a = { };
int[] b = { 3, 2, 5 };
int[] c = { 1, 8, };
var result = a.Zip3(b, c, Min3);
CollectionAssert.AreEqual(new int[0], result.ToArray());
}
[TestMethod]
public void Zip_With_All_Arrays_Empty()
{
int[] a = { };
int[] b = { };
int[] c = { };
var result = a.Zip3(b, c, Min3);
CollectionAssert.AreEqual(new int[0], result.ToArray());
}