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を使えばいけるっぽい。
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() }");
Console.WriteLine($"list1 contains list3 ={ !list3.Except(list1).Any() }");
相手の要素から自分の要素を全部削除してみて、何も残ってなければcontainsAll………ってメンドウクサ
List<T>
ソースコードList.cs
JavaでいうArrayList<T>のこと。
C++のvectorライクな初期化方法は出来ず、非常になんか、中途半端なコレクション初期化子で初期化する。
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>(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かな。