DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

配列やコレクション内に指定された要素があるか調べる

ここでは、配列やコレクションの中に指定された値と同じ要素があるか調べる方法を紹介します。また、指定した条件にあった要素があるかを調べる方法も紹介します。

ここで紹介する方法はその要素が存在するかだけを調べ、その位置(インデックス)までは調べません。位置を調べる方法は、「配列やコレクション内に指定された要素があるか調べ、その位置を知る」で説明しています。

IndexOfメソッドを使用する方法

IndexOfメソッドは配列やコレクション内での要素の位置を調べるメソッドですが、これが 0 以上の値を返すかによってその要素が存在しているかを調べることができます。

IndexOfメソッドは、EqualsメソッドがTrueを返す要素を探します。順次検索のため、O(n)操作です。

以下の例では、String型の配列内に指定した文字列の要素が存在しているかを調べています。

VB.NET
コードを隠すコードを選択
'検索元の配列
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
C#
コードを隠すコードを選択
//検索元の配列
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メソッドを使用する方法

指定した値と同じ要素がコレクション内に存在するかを調べるメソッドに、Containsメソッドがあります。存在すればtrueを、しなければfalseを返します。

ContainsメソッドもEqualsメソッドを使って一致する要素を検索します。これも順次検索のため、O(n)操作です。

VB.NET
コードを隠すコードを選択
'検索元の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"を返す
C#
コードを隠すコードを選択
//検索元の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を呼び出す例を示します。

VB.NET
コードを隠すコードを選択
'検索元の配列を作成
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
C#
コードを隠すコードを選択
//検索元の配列を作成
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名前空間をインポートします。

VB.NET
コードを隠すコードを選択
'Imports System.Linq
'がソースファイルの一番上に書かれているものとする 

'配列を作成 
Dim ary As String() = New String() {"a", "b", "c"}

'"a"が配列に含まれているか調べる 
If ary.Contains("a") Then
    Console.WriteLine("見つかりました。")
End If
C#
コードを隠すコードを選択
//using System.Linq;
//がソースファイルの一番上に書かれているものとする

//配列を作成
string[] ary = new string[] { "a", "b", "c" };

//"a"が配列に含まれているか調べる
if (ary.Contains("a"))
{
    Console.WriteLine("見つかりました。");
}

IEqualityComparerを指定して、一致する条件を変更する

上記のLINQの方法では、IEqualityComparer<T>を指定することにより、探す値と要素が等しいと判断する条件を変更することができます。

以下に、ひらがなとカタカナ、全角と半角を区別しないで検索できるようにするIEqualityComparer<T>を実装したクラスの例を示します。なお、EqualsやGetHashCodeメソッドのオーバーライドについては「自作クラスのEqualsメソッドをオーバーライドして、等価の定義を変更する」を、ひらがなとカタカナ、全角と半角を区別しないで文字列を比較する方法は「大文字小文字、半角全角、ひらがなカタカナの区別をしないで文字列を比較する」を参考にしてください。

VB.NET
コードを隠すコードを選択
''' <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
C#
コードを隠すコードを選択
/// <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メソッドを呼び出すには、次のようにします。

VB.NET
コードを隠すコードを選択
'検索元の配列を作成
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
C#
コードを隠すコードを選択
//検索元の配列を作成
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("見つかりました。");
}

StringComparerクラスを使って、大文字と小文字を区別しないで検索する

大文字と小文字を区別しない検索や、カルチャに依存しない検索ならば、IEqualityComparerインターフェイスが実装されたクラスがStringComparerクラスにあらかじめ用意されていますので、それを使うと楽ができます。

以下に示す例では、StringComparer.OrdinalIgnoreCaseを使うことで、大文字と小文字を区別せずに配列から文字列を検索しています。

VB.NET
コードを隠すコードを選択
'配列を作成
Dim ary As String() = New String() {"b", "aaaaa", "cc"}

'大文字と小文字を区別せずに文字列が配列に含まれているか調べる
If ary.Contains("Aaaaa", StringComparer.OrdinalIgnoreCase) Then
    Console.WriteLine("見つかりました。")
End If
C#
コードを隠すコードを選択
//配列を作成
string[] ary = new string[] { "b", "aaaaa", "cc" };

//大文字と小文字を区別せずに文字列が配列に含まれているか調べる
if (ary.Contains("Aaaaa", StringComparer.OrdinalIgnoreCase))
{
    Console.WriteLine("見つかりました。");
}

Existsメソッドを使用する方法

ここからは、指定した条件に合致した要素が存在するかを調べる方法を紹介します。

Existsメソッドは、条件を指定して検索するメソッドです。条件に合った要素が1つでも見つかれば、Trueを返します。このメソッドは、.NET Framework 2.0以降で使用できます。

Existsメソッドは、配列の場合は、スタティックメソッド(Array.Exists<T>メソッド)です。コレクションでは、List(List<T>.Existsメソッド)で使用でき、こちらはインスタンスメソッドです。

Existsメソッドを使うには、検索条件に合致したときにTrueを返すメソッドを作成します。このメソッドは、Predicateジェネリックデリゲートと同じシグネチャである必要があります。

Existsメソッドも順次検索ですので、O(n)操作です。

例を見た方が分かりやすいと思いますので、早速ですが、例を示します。ここでは、長さが1の文字列を検索しています。

VB.NET
コードを隠すコードを選択
'文字列の長さが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
C#
コードを隠すコードを選択
//文字列の長さが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では使えません。

C#
コードを隠すコードを選択
//検索元の配列を作成
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以降)、次のようにさらに簡単に記述することができます。

VB.NET
コードを隠すコードを選択
'検索元の配列を作成 
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
C#
コードを隠すコードを選択
//検索元の配列を作成
string[] ary = new string[] { "b", "aaaaa", "cc" };

//文字列の長さが1の要素を検索
if (Array.Exists(ary, s => s.Length == 1))
{
    Console.WriteLine("長さが1の要素が見つかりました。");
}

Anyメソッドを使用する方法

.NET Framework 3.5以降でLINQを使えるのであれば、Anyメソッドが便利です。

以下に、文字列の長さが1の要素が含まれているかを調べる例を示します。

VB.NET
コードを隠すコードを選択
'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
C#
コードを隠すコードを選択
//using System.Linq;
//がソースファイルの一番上に書かれているものとする

//検索元の配列(コレクションでも可)
string[] ary = new string[] { "b", "aaaaa", "cc" };

//長さが1の文字列を探す
if (ary.Any(s => s.Length == 1))
{
    Console.WriteLine("見つかりました。");
}

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • 「???を参照に追加します」の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。