うら干物書き

ゲームを作りたい!

【C#,LINQ】Zip~別の型の配列やリストを合体して新しい型のシーケンスを作りたいとき~

 C#のLINQの関数であるZip()の使い方についてです。
 異なる型の配列やリストを合体して、新たなシーケンスを作成することが出来ます。
f:id:urahimono:20180721065357p:plain


この記事には.NET Framework 4.6.1を使用しています。

さあ、合体だ

 巨大な敵が現れた場合、あなたはどうしますか。
 当然のことながら、仲間たちと合体して巨大ロボになることが最適解ですよね。
 ですが、それでも巨大な敵が倒せないとしたら、どうすればよいのでしょうか。
 そうですね、変形すればいいんですよね。

 LINQのZip()は異なる型の配列やリストを組み合わせて、新しい型のシーケンスを作成することができます。

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>( this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector );
https://msdn.microsoft.com/ja-jp/library/dd267698.aspx

 使い方としては、
 第一引数に、合体する配列やリストといったシーケンスを。
 第二引数に、二つの要素を合体する処理を記述します。

 合体する要素の選抜は、各シーケンスの同じインデックスの要素が合体されます。
 そのため作られるシーケンスは、少ないほうのシーケンスの数に合わせられます。

 以下の例では合体処理にラムダ式を用いて記述しています。

Program.cs

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

public static class Program
{
    static void Main( string[] args )
    {
        // 数字データと文字列データ
        int[]       numbers = new int[]    { 1, 2, 3, 4 };
        string[]    texts   = new string[] { "A", "B", "C" };

        IEnumerable<string> results = numbers.Zip( texts,
                                                  ( number, text ) => string.Format( "{0}{1}", number.ToString(), text ) );

        // 結果発表
        System.Console.WriteLine( "numbers:{0}", numbers.Text() );
        System.Console.WriteLine( "texts  :{0}", texts.Text() );
        System.Console.WriteLine( "results:{0}", results.Text() );

        // 入力待ち用
        System.Console.ReadKey();
    }

    /// <summary>
    /// 簡易的なコレクションのテキスト取得処理
    /// </summary>
    public static string Text( this IEnumerable i_source )
    {
        string text = string.Empty;
        foreach( var value in i_source )
        {
            text += string.Format( "[{0}], ", value );
        }
        return text;
    }

} // class Program

numbers:[1], [2], [3], [4],
texts :[A], [B], [C],
results:[1A], [2B], [3C],

 数値と文字列を合わせて、最終的に文字列のシーケンスに変形させています。

Program.cs

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

public static class Program
{
    static void Main( string[] args )
    {
        // 数字データと文字列データ
        int[]   numbersA = new int[]   { 1, 2, 3 };
        float[] numbersB = new float[] { 0.0f, 0.5f };

        IEnumerable<string> results = numbersA.Zip( numbersB,
                                                  ( numberA, numberB ) => ( numberA + numberB ).ToString() );

        // 結果発表
        System.Console.WriteLine( "numbersA:{0}", numbersA.Text() );
        System.Console.WriteLine( "numbersB:{0}", numbersB.Text() );
        System.Console.WriteLine( "results :{0}", results.Text() );

        // 入力待ち用
        System.Console.ReadKey();
    }

    /// <summary>
    /// 簡易的なコレクションのテキスト取得処理
    /// </summary>
    public static string Text( this IEnumerable i_source )
    {
        string text = string.Empty;
        foreach( var value in i_source )
        {
            text += string.Format( "[{0}], ", value );
        }
        return text;
    }

} // class Program

numbersA:[1], [2], [3],
numbersB:[0], [0.5],
results :[1], [2.5],

 このように、各シーケンスと別の型のシーケンスに変形することもできます。

 こんな感じでZip()を七兆回ほど使って、世のシーケンスを変形しまくってください。

LINQのリンク