ここでは、配列やコレクションの中に指定された値と同じ要素があるか調べる方法を紹介します。また、指定した条件にあった要素があるかを調べる方法も紹介します。
ここで紹介する方法はその要素が存在するかだけを調べ、その位置(インデックス)までは調べません。位置を調べる方法は、「配列やコレクション内に指定された要素があるか調べ、その位置を知る」で説明しています。
IndexOfメソッドは配列やコレクション内での要素の位置を調べるメソッドですが、これが 0 以上の値を返すかによってその要素が存在しているかを調べることができます。
IndexOfメソッドは、EqualsメソッドがTrueを返す要素を探します。順次検索のため、O(n)操作です。
以下の例では、String型の配列内に指定した文字列の要素が存在しているかを調べています。
'検索元の配列 Dim ary As String() = New String() {"red", "blue", "white", "blue", "red"} 'ary内に"blue"が存在しているか調べる If 0 <= Array.IndexOf(ary, "blue") Then Console.WriteLine("一致する要素が見つかりました") Else Console.WriteLine("一致する要素が見つかりませんでした") End If
//検索元の配列 string[] ary = new string[] { "red", "blue", "white", "blue", "red" }; //ary内に"blue"が存在しているか調べる if (0 <= Array.IndexOf(ary, "blue")) { Console.WriteLine("一致する要素が見つかりました"); } else { Console.WriteLine("一致する要素が見つかりませんでした"); }
配列やコレクション内での要素の位置を調べるメソッドには、IndexOfメソッドの他にBinarySearchメソッドなどもあります。詳しくは「配列やコレクション内に指定された要素があるか調べ、その位置を知る」をご覧ください。
指定した値と同じ要素がコレクション内に存在するかを調べるメソッドに、Containsメソッドがあります。存在すればtrueを、しなければfalseを返します。
ContainsメソッドもEqualsメソッドを使って一致する要素を検索します。これも順次検索のため、O(n)操作です。
'検索元のArrayListを作成する Dim al As New System.Collections.ArrayList() al.Add("aaaaa") al.Add("b") al.Add("cc") 'al内に"cc"があるか調べる Dim b1 As Boolean = al.Contains("cc") 'あるので、"true"を返す 'al内に"a"があるか調べる Dim b2 As Boolean = al.Contains("a") 'ないので、"false"を返す
//検索元のArrayListを作成する System.Collections.ArrayList al = new System.Collections.ArrayList(); al.Add("b"); al.Add("aaaaa"); al.Add("cc"); //al内に"cc"があるか調べる bool b1 = al.Contains("cc"); //あるので、"true"を返す //al内に"a"があるか調べる bool b2 = al.Contains("a"); //ないので、"false"を返す
ArrayクラスにはContainsメソッドがありません。配列でContainsメソッドを使用するには、IList<T>インターフェイスのContainsメソッドを使用するか、LINQ(Enumerable.Contains<TSource>メソッド)を使用します。IListの場合は.NET Framework 2.0以降、LINQの場合は3.5以降で使用できます。
IListのContainsを呼び出す例を示します。
'検索元の配列を作成 Dim ary As String() = New String() {"a", "b", "c"} '"a"が配列に含まれているか調べる If DirectCast(ary, System.Collections.Generic.IList(Of String)).Contains("a") Then Console.WriteLine("見つかりました。") End If
//検索元の配列を作成 string[] ary = new string[] { "a", "b", "c" }; //"a"が配列に含まれているか調べる if (((System.Collections.Generic.IList<string>)ary).Contains("a")) { Console.WriteLine("見つかりました。"); }
LINQを使用する場合は、参照設定に「System.Core.dll」を追加し、System.Linq名前空間をインポートします。
'Imports System.Linq 'がソースファイルの一番上に書かれているものとする '配列を作成 Dim ary As String() = New String() {"a", "b", "c"} '"a"が配列に含まれているか調べる If ary.Contains("a") Then Console.WriteLine("見つかりました。") End If
//using System.Linq; //がソースファイルの一番上に書かれているものとする //配列を作成 string[] ary = new string[] { "a", "b", "c" }; //"a"が配列に含まれているか調べる if (ary.Contains("a")) { Console.WriteLine("見つかりました。"); }
上記のLINQの方法では、IEqualityComparer<T>を指定することにより、探す値と要素が等しいと判断する条件を変更することができます。
以下に、ひらがなとカタカナ、全角と半角を区別しないで検索できるようにするIEqualityComparer<T>を実装したクラスの例を示します。なお、EqualsやGetHashCodeメソッドのオーバーライドについては「自作クラスのEqualsメソッドをオーバーライドして、等価の定義を変更する」を、ひらがなとカタカナ、全角と半角を区別しないで文字列を比較する方法は「大文字小文字、半角全角、ひらがなカタカナの区別をしないで文字列を比較する」を参考にしてください。
''' <summary> ''' カルチャと比較オプションを指定できるIEqualityComparerを実装したクラス ''' </summary> Public Class CultureInfoEqualityComparer Implements System.Collections.Generic.IEqualityComparer(Of String) Private _compareInfo As System.Globalization.CultureInfo Private _compareOptions As System.Globalization.CompareOptions ''' <summary> ''' CultureInfoEqualityComparerのコンストラクタ ''' </summary> ''' <param name="culture">比較で使用するカルチャ</param> ''' <param name="options">比較で使用するオプション</param> Public Sub New(ByVal culture As System.Globalization.CultureInfo, _ ByVal options As System.Globalization.CompareOptions) Me._compareInfo = culture Me._compareOptions = options End Sub 'Compareが0を返す時にTrueを返す Public Overloads Function Equals(ByVal x As String, ByVal y As String) As Boolean _ Implements System.Collections.Generic.IEqualityComparer(Of String).Equals If Object.ReferenceEquals(x, y) Then Return True End If If x Is Nothing OrElse y Is Nothing Then Return False End If Return Me._compareInfo.CompareInfo.Compare(x, y, Me._compareOptions) = 0 End Function 'EqualsがTrueの時は必ず同じ値を返す Public Overloads Function GetHashCode(ByVal obj As String) As Integer _ Implements System.Collections.Generic.IEqualityComparer(Of String).GetHashCode '簡単に計算する方法が分からないので、とりあえず定数を返す If obj Is Nothing Then Return 0 End If Return 1 End Function End Class
/// <summary> /// カルチャと比較オプションを指定できるIEqualityComparerを実装したクラス /// </summary> public class CultureInfoEqualityComparer : System.Collections.Generic.IEqualityComparer<string> { private System.Globalization.CultureInfo _compareInfo; private System.Globalization.CompareOptions _compareOptions; /// <summary> /// CultureInfoEqualityComparerのコンストラクタ /// </summary> /// <param name="culture">比較で使用するカルチャ</param> /// <param name="options">比較で使用するオプション</param> public CultureInfoEqualityComparer( System.Globalization.CultureInfo culture, System.Globalization.CompareOptions options) { this._compareInfo = culture; this._compareOptions = options; } //Compareが0を返す時にTrueを返す public bool Equals(string x, string y) { if (object.ReferenceEquals(x, y)) { return true; } if (x == null || y == null) { return false; } return this._compareInfo.CompareInfo.Compare( x, y, this._compareOptions) == 0; } //EqualsがTrueの時は必ず同じ値を返す public int GetHashCode(string obj) { //簡単に計算する方法が分からないので、とりあえず定数を返す if (obj == null) { return 0; } return 1; } }
このクラスを使用してContainsメソッドを呼び出すには、次のようにします。
'検索元の配列を作成 Dim ary As String() = New String() {"あ", "い", "う"} '日本語カルチャで、ひらがなとカタカナ、半角と全角を区別しない 'CultureInfoEqualityComparerを作成 Dim cmp As New CultureInfoEqualityComparer( _ New System.Globalization.CultureInfo("ja-JP"), _ System.Globalization.CompareOptions.IgnoreKanaType Or _ System.Globalization.CompareOptions.IgnoreWidth) '検索する If ary.Contains("ウ", cmp) Then Console.WriteLine("見つかりました。") End If
//検索元の配列を作成 string[] ary = new string[] { "あ", "い", "う" }; //日本語カルチャで、ひらがなとカタカナ、半角と全角を区別しない //CultureInfoEqualityComparerを作成 CultureInfoEqualityComparer cmp = new CultureInfoEqualityComparer( new System.Globalization.CultureInfo("ja-JP"), System.Globalization.CompareOptions.IgnoreKanaType | System.Globalization.CompareOptions.IgnoreWidth); //検索する if (ary.Contains("ウ", cmp)) { Console.WriteLine("見つかりました。"); }
大文字と小文字を区別しない検索や、カルチャに依存しない検索ならば、IEqualityComparerインターフェイスが実装されたクラスがStringComparerクラスにあらかじめ用意されていますので、それを使うと楽ができます。
以下に示す例では、StringComparer.OrdinalIgnoreCaseを使うことで、大文字と小文字を区別せずに配列から文字列を検索しています。
'配列を作成 Dim ary As String() = New String() {"b", "aaaaa", "cc"} '大文字と小文字を区別せずに文字列が配列に含まれているか調べる If ary.Contains("Aaaaa", StringComparer.OrdinalIgnoreCase) Then Console.WriteLine("見つかりました。") End If
//配列を作成 string[] ary = new string[] { "b", "aaaaa", "cc" }; //大文字と小文字を区別せずに文字列が配列に含まれているか調べる if (ary.Contains("Aaaaa", StringComparer.OrdinalIgnoreCase)) { Console.WriteLine("見つかりました。"); }
ここからは、指定した条件に合致した要素が存在するかを調べる方法を紹介します。
Existsメソッドは、条件を指定して検索するメソッドです。条件に合った要素が1つでも見つかれば、Trueを返します。このメソッドは、.NET Framework 2.0以降で使用できます。
Existsメソッドは、配列の場合は、スタティックメソッド(Array.Exists<T>メソッド)です。コレクションでは、List(List<T>.Existsメソッド)で使用でき、こちらはインスタンスメソッドです。
Existsメソッドを使うには、検索条件に合致したときにTrueを返すメソッドを作成します。このメソッドは、Predicateジェネリックデリゲートと同じシグネチャである必要があります。
Existsメソッドも順次検索ですので、O(n)操作です。
例を見た方が分かりやすいと思いますので、早速ですが、例を示します。ここでは、長さが1の文字列を検索しています。
'文字列の長さが1か調べるメソッド Private Function IsLengthOne(ByVal str As String) As Boolean Return str.Length = 1 End Function 'Button1のClickイベントハンドラ Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles Button1.Click '検索元の配列を作成 Dim ary As String() = New String() {"b", "aaaaa", "cc"} '文字列の長さが1の要素を検索 If Array.Exists(ary, AddressOf Me.IsLengthOne) Then Console.WriteLine("長さが1の要素が見つかりました。") End If End Sub
//文字列の長さが1か調べるメソッド private bool IsLengthOne(string str) { return str.Length == 1; } //Button1のClickイベントハンドラ private void Button1_Click(object sender, System.EventArgs e) { //検索元の配列を作成 string[] ary = new string[] { "b", "aaaaa", "cc" }; //文字列の長さが1の要素を検索 if (Array.Exists(ary, this.IsLengthOne)) { Console.WriteLine("長さが1の要素が見つかりました。"); } }
C#では、匿名メソッドを使うともっと簡単に記述できます。残念ながら、匿名メソッドはVB.NETでは使えません。
//検索元の配列を作成 string[] ary = new string[] { "b", "aaaaa", "cc" }; //文字列の長さが1の要素を検索 if (Array.Exists(ary, delegate(string s) { return s.Length == 1; })) { Console.WriteLine("長さが1の要素が見つかりました。"); }
ラムダ式が使えるのであれば(VB9、C#3.0、.NET Framework 3.5、Visual Studio 2008以降)、次のようにさらに簡単に記述することができます。
'検索元の配列を作成 Dim ary As String() = New String() {"b", "aaaaa", "cc"} '文字列の長さが1の要素を検索 If Array.Exists(ary, Function(s As String) s.Length = 1) Then Console.WriteLine("長さが1の要素が見つかりました。") End If
//検索元の配列を作成 string[] ary = new string[] { "b", "aaaaa", "cc" }; //文字列の長さが1の要素を検索 if (Array.Exists(ary, s => s.Length == 1)) { Console.WriteLine("長さが1の要素が見つかりました。"); }
.NET Framework 3.5以降でLINQを使えるのであれば、Anyメソッドが便利です。
以下に、文字列の長さが1の要素が含まれているかを調べる例を示します。
'Imports System.Linq 'がソースファイルの一番上に書かれているものとする '検索元の配列(コレクションでも可) Dim ary As String() = New String() {"b", "aaaaa", "cc"} '長さが1の文字列を探す If ary.Any(Function(s) s.Length = 1) Then Console.WriteLine("見つかりました。") End If
//using System.Linq; //がソースファイルの一番上に書かれているものとする //検索元の配列(コレクションでも可) string[] ary = new string[] { "b", "aaaaa", "cc" }; //長さが1の文字列を探す if (ary.Any(s => s.Length == 1)) { Console.WriteLine("見つかりました。"); }
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。