Javaを離れて(といいつつ毎週何回かはEclipseが立ち上がる)、思うのだが
.Netのドキュメントが読みづらいことこの上ない。
なんで、戻り値の型とか、一々関数の説明見に行かないと見えないんだ? ローカル変数の型はvarで省略出来るとか関係ない。 ドキュメントを読んでるとき、そこからリンクを辿って色々クラスを見ることが結構重要だ。 だが、.Netでそれをするのは非常にしんどい。サイトが開くのが遅い上に、何度もジャンプしないといけないとか勘弁してくれ。
JavaDocに慣れてるからじゃなくて、圧倒的にJavaDocの方が優れているのは間違いないと思う。 Doxygenで書いた方がいいんじゃないかってレベル。
とりあえず、ブログじゃねぇんだから3カラムは耐えられない。一先ずは、ユーザースタイルシートで誤魔化したけど。
というわけで、今日はC#のリスト
C#のリスト
C#でリストを使うには以下を宣言しておく。
using System.Collections.Generic;
ソースコードはここ.Net Frameworkはソースコード探しやすいのに、coreのはないのかなぁ。
IList
JavaでいうList
JavaのList | C#のIList |
---|---|
add(value) | Add(value) |
clear() | Clear() |
contains(value) | Contains(value) |
containsAll(collection) | |
get(index) | list[index] |
indexOf(value) | IndexOf(value) |
insert(index,value) | Insert(index,value) |
isEmpty() | |
remove(index) | RemoveAt(index) |
remove(value) | Remove(value) |
size() | Count |
subList(from,to) | |
set(index,value) | list[index]=value |
toArray() |
toArrayとかはList<T>とかで実装されてるけど、IListとしてはないっぽい。
というか、subListがないのね。Spanが使えるかと思ったけど、使えないみたい。
一応、GetRangeというメソッドがsubListに似た動作をするけど、コピーを作ってしまう。
conatinsAllは実装されていないが、Linqを使えばいけるっぽい。
// using System.Linqが必要 var list1 = new List<int>{1,2,3,4,5,6,7,8,9}; var list2 = new List<int>{1,3,5,7,9}; var list3 = new List<int>{1,3,-5,7,9}; Console.WriteLine($"list1 contains list2 ={ !list2.Except(list1).Any() }");//true Console.WriteLine($"list1 contains list3 ={ !list3.Except(list1).Any() }");//false
相手の要素から自分の要素を全部削除してみて、何も残ってなければcontainsAll………ってメンドウクサ
List<T>
ソースコードList.cs
JavaでいうArrayList<T>のこと。
C++のvectorライクな初期化方法は出来ず、非常になんか、中途半端なコレクション初期化子で初期化する。
// List<int> list{1,2,3}; これ駄目らしい var list = new List<int>{1,2,3,4};
ildasm.exeでデアセンブルしたところ、new List<int>(new int[]{1,2,3,4})ではなく、以下の様になる。
var list = new List<int>(); list.Add(1); list.Add(2); list.Add(3); list.Add(4);
う~ん。まぁ、きっと最適化されて大したことはないのでしょう。
Javaと違い、Sort関数、Reverse関数などが実装されている。(Java8からはsortは追加されたけど)
LinkedList<T>
JavaのLinkedList。ソースコードはこれなんかな?
Addを実装してない為、コレクション初期化子を使うとエラーになる。 ………え、Addがないってどういうこと。AddLastをAddにしちゃあかんかったん?うーん、わからん。
//var list = new LinkedList<int>{1,2,3}; エラー var list = new LinkedList<int>(new int[]{1,2,3});
JavaのLinkedListと違い、いわゆるPairデータ(LinkedListNode)を直に弄る。 JavaよりLispに近いデータ操作方法で、抽象化が低い。list.CDDDARとか書かせて欲しい。
var llist = new LinkedList<string>(new string[]{"a","b","c","d"}); var third = llist.First.Next.Next; Console.WriteLine($"3rd = {third.Value}");
しかし、なんでこんなインターフェースなんかなぁ。Javaの方が優秀だと思うんだよなぁ。 リンクリスト形式のデータ構造を作る時に便利かなとか思ったけど、ぶっちゃけ、自前のクラス内でリンク構造作った方が楽なんだよな。
特に実装しなくてもforeachやLinqを使う場合に便利だったりとか、そんな感じ?う~ん…
StackとQueue
後入れ先出し(LIFO)と先入れ先出し(FIFO)のデータ構造。ソースコードはStackはこれ、Queueはこれかな?
一応LinkedListでもStackとQueueは作れるけど、これらのクラスは配列でデータを保持しているから、効率が多分良い。
当然、Add関数はないのでコレクション初期化子は使えな………って、いい加減にしろよ。C++を見習え!
Stack
Java Stack | C# Stack |
---|---|
size() | Count |
pop() | Pop() |
push(item) | Push(item) |
Queue
Java Queue | C# Queue |
---|---|
size() | Count |
element() | Peek() |
peek() | 一応tryPeek(out result)がそれっぽい |
poll() | Dequeue() |
add(item) | Enqueue(item) |
tryPeekめんどい。
Immutable
ImmutableなリストはSystem.Collections.Immutableで提供されている。ソースコードはこれかな?
利用するにはnugetでインストールする必要がある。(以下のコマンド)
dotnet add package System.Collections.Immutable
リストとしてはImmutableArray構造体とImmutableListクラスがある。
どちらもコンストラクタはないので、Createを使うか、Builderを使う。
var array = ImmutableArray.Create(1,2,3,4,5); var builder = ImmutableList.CreateBuilder<string>(); builder.Add("a");builder.Add("b");builder.Add("c"); var list =builder.ToImmutableList();
実装を読むと、ImmutableArrayは中身は配列で、ImmutableListは2分木構造になっている模様。なので、ImmutableArrayはアクセスがO(1)、ImmutableListはO(logn)。
基本的にはImmutableArrayで良いかなって思う。 Immutableなリストって基本的に最初に作ったらアクセスしかないし。foreachとかはメモ化して高速化してるみたいだけど、それでもやっぱりImmutableArrayの方が単純で速いハズ。
Addなどの操作メソッドに関しては、ImmutableArrayもImmutableListも変更の代わりに、新たなリストを返す。この辺はJavaのPaguroと同じだね。でも、やっぱりサブリストはない。不変なんだから、サブリストあっても良いんじゃないんですかねぇ。
ところで、注意点はImmutableArrayって 構造体
だよね。
つまり、値型なので、引数として受け取る場合にはinで受け取らないと無駄なコピーが出来る。 でも、ImmutableArrayの中身って配列(参照型)しかないっぽいから、実はコピーの方が早かったりするんだろうか?その辺りどうなんだろう?
ImmutableStackとImmutableQueueについては、中身は配列だった。後はだいたい同様。
次はDictionary(Map)とSetかな。