いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Linq入門記-39 (LINQ To Object, Zip, 4.0で追加されたメソッド)


今回は、Zip拡張メソッドについてです。
この拡張メソッドは、.NET 4.0で追加されました。


Zip拡張メソッドは、簡単に言うと、2つのシーケンスを同時にループしてくれる拡張メソッドです。
Pythonのzip関数と同じです。


これを利用すると、複数のシーケンスをループする際にシンプルに記述出来たりします。


書式は以下の通り。

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
	this IEnumerable<TFirst> first,
	IEnumerable<TSecond> second,
	Func<TFirst, TSecond, TResult> resultSelector
)


resultSelectorにて、結果のデータを決定します。
引数には、(一つ目のシーケンスの現在の要素, 2つ目のシーケンスの現在の要素)が渡されます。


Zip拡張メソッドには、ひとつだけ注意点があります。
MSDNにも記述されているのですが、このメソッドは

どちらかのシーケンスの要素が終わるまで、処理を続ける.

という動きになっています。
なので、2つのシーケンスの要素数が異なる場合、要素数が少ない方のシーケンス分だけ
ループされます。

以下、サンプルです。

    #region LinqSamples-36
    public class LinqSamples36 : IExecutable
    {
        public void Execute()
        {
            //
            // Zip拡張メソッド.
            //
            // Zip拡張メソッドは、Pythonのzip関数と同じ動きをするものである。
            // つまり、2つのシーケンスを同時にループさせることが出来る。
            //
            // 第二引数には、resultSelectorを指定する必要があり、好きなデータを返す事ができる。
            //
            // このメソッドは、どちらかのシーケンスが終わるまで処理を続けるという仕様になっているので
            // 2つのシーケンスの要素数が異なる場合は、注意が必要である。
            //
            // つまり、片方のシーケンスが空の場合、このメソッドは一度もループされない。
            //
            IEnumerable<int> numbers1 = new int[]{ 1, 2, 3, 4, 5 };
            IEnumerable<int> numbers2 = new int[]{ 6, 7, 8, 9, 0 };
            
            var query = numbers1.Zip(numbers2, (first, second) => Tuple.Create(first, second));
            
            Console.WriteLine("========= 2つのシーケンスの要素数が同じ場合 ===========");
            foreach (var item in query)
            {
                Console.WriteLine("FIRST={0}, SECOND={1}", item.Item1, item.Item2);
            }
            
            numbers1 = new int[]{ 1, 2, 3 };
            numbers2 = new int[]{ 6, 7, 8, 9, 0 };
            
            query = numbers1.Zip(numbers2, (first, second) => Tuple.Create(first, second));
            
            Console.WriteLine("========= 1つ目のシーケンスの要素が2つ目よりも少ない場合 ===========");
            foreach (var item in query)
            {
                Console.WriteLine("FIRST={0}, SECOND={1}", item.Item1, item.Item2);
            }
            
            numbers1 = new int[]{ 1, 2, 3, 4, 5 };
            numbers2 = new int[]{ 6, 7, 8 };
            
            query = numbers1.Zip(numbers2, (first, second) => Tuple.Create(first, second));
            
            Console.WriteLine("========= 2つ目のシーケンスの要素が1つ目よりも少ない場合 ===========");
            foreach (var item in query)
            {
                Console.WriteLine("FIRST={0}, SECOND={1}", item.Item1, item.Item2);
            }
            
            numbers1 = Enumerable.Empty<int>();
            numbers2 = new int[]{ 6, 7, 8 };
            
            query = numbers1.Zip(numbers2, (first, second) => Tuple.Create(first, second));
            
            Console.WriteLine("========= どちらかのシーケンスが空の場合 ===========");
            foreach (var item in query)
            {
                Console.WriteLine("FIRST={0}, SECOND={1}", item.Item1, item.Item2);
            }
        }
    }
    #endregion


実行結果は以下の通りです。

  ========= 2つのシーケンスの要素数が同じ場合 ===========
  FIRST=1, SECOND=6
  FIRST=2, SECOND=7
  FIRST=3, SECOND=8
  FIRST=4, SECOND=9
  FIRST=5, SECOND=0
  ========= 1つ目のシーケンスの要素が2つ目よりも少ない場合 ===========
  FIRST=1, SECOND=6
  FIRST=2, SECOND=7
  FIRST=3, SECOND=8
  ========= 2つ目のシーケンスの要素が1つ目よりも少ない場合 ===========
  FIRST=1, SECOND=6
  FIRST=2, SECOND=7
  FIRST=3, SECOND=8
  ========= どちらかのシーケンスが空の場合 ===========

================================
過去の記事については、以下のページからご参照下さい。