エンジニアもどきの雑記

メモ帳です。きっと。macアプリ配信windowsでもできるようになるまで絶対にメイン機にしないマン。特筆しない限り環境は【win10home,i5-7200u,8g,64bit,巨乳が好き】

【C#】UnityのためにC#を一から学ぶpart4(後編)【二次元配列、ジェネリック、foreach文】


前回
dddpga1.hateblo.jp

体調不良真っただ中! 絵が下手なのは体調のせいではない! 私だよ。

今回は前回やった配列を更に進めるよ。

二次元配列をやる前に、
少し前回の補足。

配列の宣言

int[] x = new int[10];

の【new】これはnew演算子なんて言われたりします。実際、c#でもそういうのかは正直知らない……
他のオブジェクト指向言語では少なくともそう呼ぶ。

これで、メモリのヒープ上に展開している。
はず。

int[] xのx自体はメモリのスタック領域に展開されるんだけど、それが【参照】するのは
ヒープ上に展開された配列の領域。


詳しいことはまぁ、おいおい。
なんとなくこの形が頭に入ってるだけでだいぶ違う。


され、本題。進めよう。



二次元配列、とは。


簡単に言えば配列の配列です。
前回、普通の配列を扱いました。あれは一次元配列です。

配列だけ表せば以下

[ 1, 2, 3, 4, 5 ]

[]の中に数字が並んでいます。これが配列です。

int[] x = new int[5] { 1, 2, 3, 4, 5 };

つまりxは配列です。


では、以下は?

static void Main(string[] args)
{
 int[,] array = new int[5, 5];
 array[1, 3] = 60;
 Console.WriteLine(array[1, 3]);
}
// 60




これ、はい。これが二次元配列。
配列の中に配列があるような状態。
似たものでジャグ配列ってのもあるんだけど、とりあえずこっちだけまずは覚える。

これどうなっているか、って形にするとこう。

 0, 1, 2, 3, 4
0 *   *  *  *   *
1 *   *  60*  *
2 *   *  *  *   *
3 *   *  *  *   *
4 *   *  *  *   * 



とりあえずこれはなんとなく、イメージをつかめばよい。
最初はそんなもん。自分で勉強する人ならすぐに理解するし、今後解説しますん。


横に並んでる数字が、【一次元のインデックス
縦に並んでる数字が、【二次元のインデックス

です。

宣言は以下

int[,] array = new int[5, 4];

配列が[ 1, 2, 3]と表現されるように、二つのインデックスを表すのも同様にに,(カンマ)で区切ったものを表す。
[5, 4]に関しては、先に二次元のインデックスを宣言して、あとに一次元のインデックスを宣言する。
これが数字的に逆なのは初見殺し。
そこまでわかった上で、先ほどの図を見てみればなんとなくわかるでしょう。

配列の配列。
これが二次元配列。
詳しいことを語るともっと長くなるので、とりあえずこの形だけ覚えよう。


そしてforeach文。
ジェネリックの話も少ししてからね。


ジェネリックとは、超簡単に言って配列操作をするための機能。

前回、そして今回と簡単にだけどやってきた配列。
お気づきの方もいるとは思いますが、数が、増えないんだ。前回書いたかもしれないけど。


int
= new int[5];
って宣言した時点で、このxのインデックスは4より増えない。
それを補うようにしてArrayListっていうものがあったり、前に少しだけ紹介したList,Dictionaryがある。
ちなみに、今までUnityちまちまやってきて、ArrayListは使用したことがない。

なぜか。
単純にphpの配列的にListが使いやすいからである。
と、同時に、自分が学んだ限りではArrayListは要素をオブジェクトとして保持して全部キャストされるので、
処理が重くなる。

何言ってんだ、って人は、単純にプログラムが実行される速度が遅くなるので、パフォーマンスが悪くなるんだなぁ、くらいに
思っておいてください。いや、そのまんまだけど。


さて、じゃあ簡単に先に話したArrayList,List,Dictionaryを見てみよう。

【ArrayList】
ArrayList arr = new ArrayList(); //宣言
arr.Add('a');
arr.Add("stringggg");
arr.Add(40);
Console.WriteLins(arr[1]);
//srringggg


前に話さなかったけど、c#の''と、""は扱いが違います。(phpも違うけど
''はchar型の文字。""はstring型です。まぁ、文字か文字列か、ってぐらいでいいと思う。
今回違う型のものがAdd関数でArrayList型のarrに追加されています。順番に追加されています。それだけです。
先ほど少し話た通り、突っ込まれる型をすべてObject型としてArrayListは持つので、こういったものにも対応します。
ちなみに、これは要素数が決まっていないというのは先の通りで、じゃあどんな動きをしんてんのかい、っていうと
値が入る度(Addで追加される度)メモリの再割り当てがされてます。


【List】
List<string> listStr = new List<string>(); //宣言
string x = "hogehoge";
listStr.Add(x);
Console.WriteLint(listStr[0]);
// hogehoge
int y = 100;
listStr.Add(y); //ここでコンパイルエラー


ここからがジェネリックだ!
そもそもジェネリックって、俺が学んだ本によれば、
クラスをインスタンス化する際に型を指定してその型だけに対応すしたインスタンスを生成する機能
だそうだ。
ArrayListも[]による配列も、どっちも型の指定はなかったよね。
ちなみにListはListクラス。クラスなんだね。でもここら辺はまた今度説明するよ。Dictionaryも同じ。


Listは<>内で扱う型を決めます。
上記のものだと一行目でstring型だと指定しているので、今回宣言したlistStrはstring型しか扱えません。
なので最後の行のAddは失敗しています。int型は入らないよ、と。


【Dictionary】
var obj = new Dictionary<int, string>()
{
    { 1, "hoge"},
    { 2, "fuga" },
    { 3, "foo"   }
};
Console.WriteLine(obj[1]);
//hoge


phpでいう連想配列に近いもの。
key valueってやつ。
今までのものはインデクサって勝手に降られていた数字がキーになって値(value)が呼び出されていたけど、
今度はキーをこっちで指定しちゃうってやつ。
これ、単純に重いのでさくっと使うのが一番(スコープ内だけ、とか書こうと思ったけどスコープどころかクラスもやってないね)
あと、伝統的なものだけど、Dictionaryだからって
変数名にDictionary的な文字は入れない。
mapとかtableとか表現します。
例えるなら、

var objDic = new Dictionary ~ は×
var objTbl = new Dictionary ~ は〇
var objMap = new Dicitonary ~ は〇

あと、今回から出てきた【var】。これ、javascript書いてる人はめっちゃみたんではなかろうか、es6だけ書いてるとめったに使わないけど。
詳しいことはまた今度。暗黙的に型を設定してくれるものだと思っていてください。


さて、簡単にだけどそれぞれ紹介したと思う。
どれを見ても基本は一緒で、
宣言は

int[] x = int[5];
List<t> list = new List<t>();
Dictionary<k, v> map = new Dictionary<k, v>();

これ。覚える。listとdictionaryはクラスだから()が付く。ここら辺ももう覚える。Unity触りたい。


これらを取り出す手段として、前回やったfor文とは違うforeachってのがある。
それが以下。

List<int> list = new List<int>();
            
for (int i = 1; i < 10; i++)
{
    list.Add(i);
}

foreach (int num in list)
{
    Console.WriteLine(num);
}
// 1 2 3 4 5 6 7 8 9


さて、順に追っていこう
っていうかまずは書こう。書いて実行しよう。一行ずつ書いてれば流れはわかる。

まず、list型のlist変数を宣言。

for文を使用してlistに対して1~9の数字をAdd

foreach文を用いてそれらをすべて表示。


です。
foreach文はこの形。

foreach (型 配列の中身の変数名 in 中身を取り出したい配列)
{
    //繰り返し行う何か
}

もっと丁寧な説明してる本なりサイトなりが多いけど、結局これだと思ってる。
foreach文では、inの後に今回中身を取り出す配列なりオブジェクトなりを置きます。

foreach ( in list)
{
} 

今回だとこうなるね。
その中身を取り出すために、変数を用意します。

foreach (int num in list)
{
}

今回だとこう。
foreach文は配列を確認するように配列の中身を一個一個numに入れます。
一個入れて{}の中の処理を実行。
次にnumに次の値を入れて{}の中を実行。
それを配列の要素数分やってくれます。

超簡単に言うとこれ。
詳しいことが知りたい人はもっと勉強!

とりあえず、適当にListなり何なりつくって自分でforeachで回してみるといいよ。
読むのもいいけど書くに勝ることはない、多分。


さて、かなり詰め込んだけどとりあえずここまで。

もっと細かいこと沢山あって、これだけで不安だけど次はUnityやろう。