C#のLINQの関数であるCount()
, LongCount()
の使い方についてです。
シーケンスの要素数を取得することが出来ます。
この記事には.NET Framework 4.6.1を使用しています。
要素数を数える
配列やリストの中にいくつ要素が詰め込まれているのか。
配列の場合にはLength
プロパティを、リストの場合にはCount
プロパティを使うことで要素数がわかります。
LINQにもCount()
というものがあり、IEnumerable<T>
を継承したものなら使うことができます。
public static int Count<TSource>( this IEnumerable<TSource> source );
Enumerable.Count(TSource) メソッド (IEnumerable(TSource)) (System.Linq)
早速試してみましょう。
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { static void Main( string[] args ) { int[] intArray = new int[] { 1, 5, 8, 12, 15, 16 }; List<string> stringList = new List<string>() { "正一郎", "清次郎", "誠三郎", "征史郎" }; int intCount = intArray.Count(); int stringCount = stringList.Count(); // 結果発表 System.Console.WriteLine( "intArrayの数:{0}", intCount ); System.Console.WriteLine( "stringListの数:{0}", stringCount ); // 入力待ち用 System.Console.ReadKey(); } } // class Program
intArrayの数:6
stringListの数:4
簡単に使えます。
条件に合った要素数を数える
上記の使い方に加えて、数える要素に条件を追加することができます。
public static int Count<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate );
Enumerable.Count(TSource) メソッド (IEnumerable(TSource), Func(TSource, Boolean)) (System.Linq)
特定のフラグが立っている要素のみを数えたり、特定の種類のデータのみを数えたり数場合に活用できます。
以下の例では、偶数の値のみを数える場合と特定の文字の要素のみ数える処理を、ラムダ式を用いて実装しています。
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { static void Main( string[] args ) { int[] intArray = new int[] { 1, 5, 8, 12, 15, 16 }; List<string> stringList = new List<string>() { "正一郎", "清次郎", "誠三郎", "征史郎" }; // 偶数の要素の数を数えますよ。 int intCount = intArray.Count( value => value % 2 == 0 ); // "三"の文字が入っている要素の数を数えますよ。 int stringCount = stringList.Count( value => value.IndexOf( "三" ) >= 0 ); // 結果発表 System.Console.WriteLine( "intArrayの数:{0}", intCount ); System.Console.WriteLine( "stringListの数:{0}", stringCount ); // 入力待ち用 System.Console.ReadKey(); } } // class Program
intArrayの数:3
stringListの数:1
指定した条件の要素のみがカウントされました。
要素数が世界の人口数より多い場合
さてさて、先ほど紹介したCount()
なのですが、返り値の型はint
型です。
int
型ということは、正数として使える値は、えーと……、20何億かぐらいでしょうか。
では、それぐらいの要素数がある場合に、Count()
を使うとどうなってしまうのでしょうか。
試してみましょう。
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { static void Main( string[] args ) { // 0 から21億4748万3647個連続した整数のシーケンスを作るよ。 IEnumerable<int> intSequenceA = Enumerable.Range( 0, int.MaxValue ); // -21億4748万3648個 から 21億4748万3647個連続した整数のシーケンスを作るよ。 IEnumerable<int> intSequenceB = Enumerable.Range( int.MinValue, int.MaxValue ); // intSequenceAとintSequenceBを合体させた、すごい要素数のシーケンスを作成するよ。 IEnumerable<int> intSequenceAB = intSequenceA.Concat( intSequenceB ); int count = 0; try { count = intSequenceAB.Count(); } catch( System.Exception i_exception ) { System.Console.WriteLine( "例外:{0}", i_exception ); // 入力待ち用 System.Console.ReadKey(); return; } // 結果発表 System.Console.WriteLine( "intSequenceABの数:{0}", count ); // 入力待ち用 System.Console.ReadKey(); } } // class Program
例外:System.OverflowException: 算術演算の結果オーバーフローが発生しました。
さすがに数十億の要素を作ろうとすると、処理に時間が掛かる……。
ですが、結果が出ました。
例外が発生するみたいですね。
ということは、数十億単位の要素を扱う場合には、数を数えることは出来ないのでしょうか。
そんな場合にはLongCount()
というものがあります。
これならば返り値はlong
型なので、えーと……、一十百千……、兆の次ってなんだっけ……。
……とにかくとても大きな数値が扱えます。
public static long LongCount<TSource>( this IEnumerable<TSource> source );
Enumerable.LongCount(TSource) メソッド (IEnumerable(TSource)) (System.Linq)
これを使って先ほど例外が起きた処理を書き直してみましょう。
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { static void Main( string[] args ) { // 0 から21億4748万3647個連続した整数のシーケンスを作るよ。 IEnumerable<int> intSequenceA = Enumerable.Range( 0, int.MaxValue ); // -21億4748万3648個 から 21億4748万3647個連続した整数のシーケンスを作るよ。 IEnumerable<int> intSequenceB = Enumerable.Range( int.MinValue, int.MaxValue ); // intSequenceAとintSequenceBを合体させた、すごい要素数のシーケンスを作成するよ。 IEnumerable<int> intSequenceAB = intSequenceA.Concat( intSequenceB ); long count = 0; try { // intじゃ無理だ・・・、longならば! // count = intSequenceAB.Count(); count = intSequenceAB.LongCount(); } catch( System.Exception i_exception ) { System.Console.WriteLine( "例外:{0}", i_exception ); // 入力待ち用 System.Console.ReadKey(); return; } // 結果発表 System.Console.WriteLine( "intSequenceABの数:{0}", count ); // 入力待ち用 System.Console.ReadKey(); } } // class Program
intSequenceABの数:4294967294
こんどは例外が発生せず、きちんと数を数えることができました。
LongCount()
にもCount()
同様、数える要素に条件をつけることができます。
public static long LongCount<TSource>( this IEnumerable<TSource> source, Func<TSource, bool> predicate );
Enumerable.LongCount(TSource) メソッド (IEnumerable(TSource), Func(TSource, Boolean)) (System.Linq)
Program.cs
using System.Linq; using System.Collections; using System.Collections.Generic; public static class Program { static void Main( string[] args ) { // 0 から21億4748万3647個連続した整数のシーケンスを作るよ。 IEnumerable<int> intSequenceA = Enumerable.Range( 0, int.MaxValue ); // -21億4748万3648個 から 21億4748万3647個連続した整数のシーケンスを作るよ。 IEnumerable<int> intSequenceB = Enumerable.Range( int.MinValue, int.MaxValue ); // intSequenceAとintSequenceBを合体させた、すごい要素数のシーケンスを作成するよ。 IEnumerable<int> intSequenceAB = intSequenceA.Concat( intSequenceB ); long count = 0; try { // -100万より大きい値の数を調べてみよう! count = intSequenceAB.LongCount( value => value > -1000000 ); } catch( System.Exception i_exception ) { System.Console.WriteLine( "例外:{0}", i_exception ); // 入力待ち用 System.Console.ReadKey(); return; } // 結果発表 System.Console.WriteLine( "intSequenceABの数:{0}", count ); // 入力待ち用 System.Console.ReadKey(); } } // class Program
intSequenceABの数:2148483645
ちなみにLongCount()
もlong
型で扱える正数の値を超える場合は例外が発生するみたいです。
……試しはしませんよ。
数十億ですら、処理に結構時間が掛かったのに、それ以上桁の処理を扱った場合は、私のパソコンは二度と動かなくなるような気がします。
ではあまり無茶な数の要素を扱わないようにして、Count()
とLongCount()
を七兆回ほど使ってみてください。
LINQのリンク
- LINQ一覧
www.urablog.xyz