概要

前回(『プログラミング C#』 その4 ジェネリック型)のつづき。コレクションなんてオメー、リストとかディクショナリとかセットとかキューとかイテレータのことだろう? 先日、 Effective Python で叩き込まれたばかりだぜ。

 

流し読みノート

配列

Python ではコレクションといえばいきなり list だが、こっちじゃまずは「配列」なんだよな。この配列が原始的で使いづらくてねえ。だけれどまあ我らが Python の list も裏ではこういったモノが動いているのだろう。

  • new int[ここに配列のサイズ] みたいに宣言する。サイズの限界は 0xFFFFFFF 個。
    • 他にも宣言方法がある。たとえば型は推論させてもいい。 new [] { "foo", "bar" }
    • new [] すら書かない方法もある。 string[] values = { "foo", "bar" }

推論させるやつが一番好みかなー。メソッドの引数にもそのまま渡せるしさ。

  • 配列内の検索は (Array.FindIndex(values, "foo")) >= 0 なんだって。なんじゃそりゃ。 Python なら 'foo' in values やぞ。
  • 条件を満たすものの検索は (Array.FindIndex(values, value => value > 0)) >= 0 なんだって。ああ、こういうことやろうとしたら Python も大して変わらないかも。

 

ジャグ配列

int[][] arrays = new int[5][]
{
    new[] { 1, 2 },
    new[] { 1, },
};

ああ、多次元配列のことか。 Python 以上にネストが見づらいし面倒くさいな。

 

四角形配列

int[,] grid = new int [5, 10];
var smallerGrid = new int[,]
{
    { 1, 2, 3, },
    { 4, 5, 6, },
};
var cuboid = new int[,,]
{
    {
        { 1, 2, 3, },
        { 4, 5, 6, },
    },
    {
        { 1, 2, 3, },
        { 4, 5, 6, },
    },
};

へー、これは知らんかった。配列を組み合わせて多次元配列を作るのではなくて、「多次元配列」みたいな型? を作れるのか。 grid[2,3] みたいなアクセスの仕方をする。

配列はコピーとかサイズ変更のやり方が色々あるのだけど、こんな配列使いたくないからさっさと List<T> にいこう。

 

List<T>

  • .Add があり .Remove があり…… Python の list みたいなものだ。
  • 作り方はこう。 var numbers = new List<int> { 1, 2, 3 };

 

Collection<T>

List と比較して……

  • IndexOf はあるけど、探索やソートがない。
  • リストが変更されたときが変わる機能を提供している。

 

ディクショナリ

  • 初期化はこう。 new Dictionary<string, int> { {"One", 1}, {"Two", 2} };
  • リストやディクショナリの↑のような初期化構文が書けるのは、 IEnumerable<T>Add メソッドがあるおかげである。
    • そう! こういう「へー、アレってこういうことだったんだ」を求めてオライリーを読んでいるのよねー。
  • 追加はインデクサによるものと、 Add を使うものがある。
    • もうキーがあるときに Add するとエラーになるから、もうキーがあるのがおかしいときに Add を使えばよさそう。こういう使い分け、好きよー。
  • 「このキーがあったらこの処理を行う」みたいなことするとき、「このキーがあるか?」「あるなら値を取り出す」「処理を行う」という手順を踏まないといけないが、それをクールに行う方法が以下。これはいいぞー。
int val;
if (dic.TryGetValue("KEY", out val))  // KEY がなければスキップされるし、あれば val に値が入る!
{
    Console.WriteLine(val);
}
  • ディクショナリの初期化時に StringComparer/.InvariantCultureIgnoreCase をコンストラクタにわたすと大文字小文字無視のディクショナリを作れる。
  • ディクショナリの順序は、昔の Python と同じくバラバラである。ただしこの「バラバラ」はハッシュコードによるものである。
  • ソート済みディクショナリは SortedDictionarySortedLink で作れる。後者は、こんな名前だがディクショナリだ。こいつらは追加は遅いが検索は速い。ううむ、 tips 感あるねー。
  • ↑に関連して ISet<T> にも HashSetSortedSet という、順序バラバラとソート済みの組み合わせがある。

いやー、 Python でも大好きな型だぜ。この型のおかげでぼくはクラスもインスタンスも理解できたのだ。

 

タプル

Python でおなじみの tuple は、 quintuple, sixtuple, septuple 英語を一般化したものなんだって。知らなかった。

  • 作り方はこう。 Tuple<int, string, int[], double> myTuple = Tuple.Create(42, "foo", new[] { 1, 2 }, 12.3 ); この闇鍋感すげーな。
  • このとおり各要素の型は違ってもよい。そして各要素の型もタプルの型の一部になる。
  • 要素の個数が型の一部だから2タプルと3タプルは違う型。
  • 1タプルは役に立たない。
  • 8個までいける。

 

他のコレクション

  • FIFO のキューは Queue<T>Enqueue で追加し、 Dequeue で取り除き、 Peek で取り除かず調べる。
  • LIFO のスタックは Stack<T>Push で追加し、 Pop で取り除く。
  • 両端キューは LinkedList<T>FirstLast プロパティで先頭、末尾を得られる。これは使い所がわからん。

 

小休憩

new Dictonary<string, int> って長くね? Python の型 dict, str らへんの短いネーミングって地味にグッジョブだよな。