徳島ゲーム開発ごっこ 技術ブログ

ゲームを作るために役に立ったり立たなかったりする技術を学んでいきます!

【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のリンク