結論
Count
を使います。
List<string> dataList = new List<string>();
var dataCount = dataList.Count;
//取得結果はint型で0が取得されます。
Dictionary<int, string> dataDictionary = new Dictionary<int, string>();
var dataCount = dataDictionary.Count;
//取得結果はint型で0が取得されます。
解説
実は格納されているデータ数を取得する方法は2種類あります。
Count
とCount()
です。
何が違うのか簡単に説明しますが、基本的にはCount
を使ってください。
まず、Count
はプロパティです。そしてCount()
はメソッド(関数)です。
Count
は参照するListの内容が変化した瞬間に変化します。例えばListにデータをAddした場合です。(Removeなどでデータを削除した場合も同様です。)
List<string> dataList = new List<string>();
//Listに文字列を追加する。
dataList.Add("Apex楽しい...");
//↑この時点でCountプロパティの内容が1に変わっています。
var dataCount = dataList.Count;
//↑データ数は1らしいで^ ^
Count()
はデータ数をしようとした瞬間に改めてデータを確認します。
List<string> dataList = new List<string>();
var dataCount = dataList.Count();
//↑じゃあ、今からデータ数を数えるからちょっとまってな^ ^
//↑データ数は0やったで^ ^
処理速度の差
実際にどれくらい処理速度が違うのか検証してみました。
結果は
種類 | 実行時間[ms] | 格納データ数 |
---|---|---|
Count | 0 | 0 |
Count() | 0 | 0 |
Count | 0 | 10000 |
Count() | 0 | 10000 |
Count | 0 | 2146435071 |
Count() | 0 | 2146435071 |
...あ、あれ?
処理速度変わんないの...?
じゃあ、マイクロ秒表示するように変更して...
種類 | 実行時間[us] | 格納データ数 |
---|---|---|
Count | 10 | 0 |
Count() | 30 | 0 |
Count | 6 | 10000 |
Count() | 29 | 10000 |
Count | 38 | 2146435071 |
Count() | 21 | 2146435071 |
...(·ε·`)あんまり変わらないっぽい。
ただ、インテリセンス君がCount
を使え!!って言っているのでCount
でいいんだと思います。
追記(2022/02/07)
コメントでICollection
インタフェースを実装している型(List型やDictionary型)の場合、Count()
のメソッド内でCount
プロパティを参照しているとご指摘いただいたので改めて調べ直しました。ご指摘頂きありがとうございますm(_ _)m
Count()メソッドの内部実装
Count()
メソッドの内部実装を調べた結果、下記のように実装されていました。
public static int Count<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
ICollection<TSource> collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count;
ICollection collection = source as ICollection;
if (collection != null) return collection.Count;
int count = 0;
using (IEnumerator<TSource> e = source.GetEnumerator()) {
checked {
while (e.MoveNext()) count++;
}
}
return count;
}
ご指摘頂いた通り、ICollection
インタフェース型に変換できる場合は
Count
プロパティを参照しているようですね!
実行速度(ICollection VS IEnumerable)
改めてICollection
インタフェースを実装している場合と
実装していない(IEnumerable
インタフェース)場合の実行速度を検証しました。
結果は
種類 | 実行時間[us] | 格納データ数 |
---|---|---|
ICollection | 19 | 0 |
IEnumerable | 390 | 0 |
ICollection | 22 | 10000 |
IEnumerable | 437 | 10000 |
ICollection | 130 | 2146435071 |
IEnumerable | 5495402 | 2146435071 |
おぉ...(´ε` )
格納データ数が多いと実行時間が全然変わってきますね...!
ということは...
List<int> dataList = new();
//変数内に2146435071個データを格納する。
dataList.AddRange(Enumerable.Repeat(0, 2146435071));
IEnumerable<int> data = dataList.Where(x => x == 0).AsEnumerable();
//100万回格納データ数を使うぞ!
for (int i = 0; i < 1000000; i++)
{
var dataCount2 = data.Count();
}
検証結果から上記のソースコードを実行完了するには
5.495402[秒] * 1000000 = 5,495,402[秒] = 1,526.5[時間] = 63[日]
かかるということになります😰
Count()
メソッドを使用しないと行けない場合は注意しないといけませんね...!対処法としてはこのようにすればいいんだと思います。
List<int> dataList = new();
//変数内に2146435071個データを格納する。
dataList.AddRange(Enumerable.Repeat(0, 2146435071));
IEnumerable<int> data = dataList.Where(x => x == 0).AsEnumerable();
//Forの外で格納データ数を数えるぞ!
var dataCount = data.Count();
//100万回格納データ数を使うぞ!
for (int i = 0; i < 1000000; i++)
{
var count = dataCount;
}
今回のご指摘で一つ勉強になりました!
余談
Listに2146435071個もデータを格納するとメモリを12.1[GB]も食われました笑
データベースに格納されているデータを全てを取得するとかで、もしかしたら発生するかもなので、こちらも今後は注意してプログラミングしたいと思いました。
以上!!!