C#で多次元配列を初期化してみた


はじめに

入院していて、暇なときにQiitaを見ていたら、C#での多次元配列・ジャグ配列の初期化を見つけたので、多次元配列の場合を想定して自分ならどうするか暇つぶしに考えてみたので、おつきあい頂ければ幸い。

実行環境

C#は、6.0を利用しています。

素直にForで書く

素直にforで書くなら概ね以下の通りかと


private static int[,] UseFor()
{
    var matrix = new int[10, 10];
    for (var x = 0; x < 10; x++)
    {
        for (var y = 0; y < 10; y++)
        {
            matrix[x, y] = -1;
        }
    }
    return matrix;
}


先に多次元配列作って、その中にforで回しながらFillするなんてことの無いコードです。

foreachを使う。

上記サンプルだと、二重ループになっているのでその部分をLINQで書き換えて、foreachで回したのが、以下のサンプル。


private static int[,] UseForEach()
{
    var matrix = new int[10, 10];
    var sequence = from x in Enumerable.Range(0, 10)
        from y in Enumerable.Range(0, 10)
        select new {x, y};

    foreach (var index in sequence)
    {
        matrix[index.x, index.y] = -1;
    }

    return matrix;
}

matrixを先に使うのは、あまり変わらず。また、ループがネストしていないので利点はあるかと。
ループをクエリ構文で作成しているのが特徴。1

答え一発

尚、どこぞの電卓では無い2
ここから先は、やればできるよ程度に見て頂ければ。

Aggregateを使う


private static int[,] UseAggregate()
{
    return (from x in Enumerable.Range(0, 10)
        from y in Enumerable.Range(0, 10)
        select new {x, y}).Aggregate(new int[10, 10], (matrix, index) =>
        {
            matrix[index.x, index.y] = -1;
            return matrix;
        });
}

Aggregateの使い方からすれば、ちと疑問が残るかもだけど、キニシナイ。

確かに、一発で出せているのだけど、Aggregateメソッド内のアキュムレータ関数がどーにも気にくわない。

毒を食らわばパラノイア♪

なので、1個拡張メソッドをこさえる。


public static class Extends
{
    public static T Repeat<T>(this T source, Action<T> action)
    {
        action(source);
        return source;
    }
}

まぁ、異論は色々あるでしょうが、今回はコレで行きます。3

で、斯様に書く


private static int[,] ParanoiacLinq() =>
    (from x in Enumerable.Range(0, 10)
        from y in Enumerable.Range(0, 10)
        select new {x, y})
        .Aggregate(new int[10, 10], (m, i) => m.Repeat(x => x[i.x, i.y] = -1));

まぁ、趣味の世界と言うことで一つ。

まとめ

個人的には、foreach当たりがバランス取れてると思います。
それ以下の方法は、やってやれないことは無い的な実験的な代物ですので。

付録:禁断のUnsafe

unsafe使える環境なら、以下でもOKかと。
個人的には,あんまりお勧めしない。


private static unsafe int[,] UseUnsafe()
{
    var matrix = new int[10, 10];

    fixed (int* ptr = &matrix[0,0])
    {
        for (int i = 0; i < 100; i++)
        {
            *(ptr + i) = -1;
        }
    }
    return matrix;
}



  1. 拡張メソッドだと、Selectの中でEnumerable.Rangeするのでちょっとあれなので、クエリ構文を使った。 

  2. 歳がばれるw(ちなみにリアルタイムじゃ見ていない。コレもずいぶん古いけどNHKの電子立国日本の自叙伝の後知恵) 

  3. 名前がかぶるとか、副作用を積極活用してるとか異論があるかと思いますが、まぁいっかなって。