第3回List<T>.FindAll(Predicate<T>)
今回はFindAllをはじめとするFind系メソッドだ。
あるArrayListに入っているデータの文字列が、数字の場合に別のArrayListに構築する想定だ。
まずは従来型のソースを見てもらおう。
1.x C#
ArrayList al = new ArrayList();
al.Add("1");
al.Add("B");
al.Add("3");
ArrayList al2 = new ArrayList();
foreach( string text in al)
{
try
{
int.Parse(text);
al2.Add(text);
}
catch
{
}
}
1.x VB
Dim al As ArrayList = New ArrayList
al.Add("1")
al.Add("B")
al.Add("3")
Dim al2 As ArrayList = New ArrayList
For Each text As String In al
Try
Int32.Parse(text)
al2.Add(text)
Catch ex As Exception
End Try
Next
1.x MC++
ArrayList __gc *al = new ArrayList();
al->Add(S"1");
al->Add(S"B");
al->Add(S"3");
ArrayList __gc *al2 = new ArrayList();
for ( int LoopCounter = 0; LoopCounter < al->Count; LoopCounter++ )
{
try
{
Int32::Parse(static_cast<String*>(al->Item[LoopCounter]));
al2->Add(static_cast<String*>(al->Item[LoopCounter]));
}
catch(Exception*)
{
}
}
従来のコーディングであれば、やはり一つ一つArrayListから取り出して評価していくことになる。
この場合取り出すべきデータなのか、そうでないのかというのは例外のキャッチで表現されているので、なんとなくわかるが、true/falseといった形で明確になっていない。
場合によってはExceptionで何か他の例外が発生するのでそれを捕まえるためかと思われてしまう。
2.0 C#
private void button1_Click(object sender, EventArgs e)
{
List<string> ls = new List<string>();
ls.Add("1");
ls.Add("B");
ls.Add("3");
Predicate<string> numsel = new Predicate<string>(NumericSelector);
List<string> ls2 = ls.FindAll(numsel);
}
public bool NumericSelector(string text)
{
try
{
int.Parse(text);
return true;
}
catch (FormatException)
{
return false;
}
}
2.0 VB
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ls As List(Of String) = New List(Of String)
ls.Add("1")
ls.Add("B")
ls.Add("3")
Dim numsel As Predicate(Of String) = New Predicate(Of String)(AddressOf NumericSelector)
Dim ls2 As List(Of String) = ls.FindAll(numsel)
End Sub
Public Function NumericSelector(ByVal text As String) As Boolean
NumericSelector = False
Try
Int32.Parse(text)
NumericSelector = True
Catch ex As Exception
End Try
End Function
private:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
List<String^>^ ls = gcnew List<String^>();
ls->Add("1");
ls->Add("B");
ls->Add("3");
Predicate<String^>^ numsel = gcnew Predicate<String^>(this, &Form1::NumericSelector);
List<String^>^ ls2 = ls->FindAll(numsel);
}
public :
bool NumericSelector(String^ text)
{
try
{
Int32::Parse(text);
return true;
}
catch(Exception^)
{
return false;
}
}
このように一部のデータを抜き出すということ(FindAll)にこのような処理を行うということがより明確になっていると思う。
このPredicateデリゲートは
delegate bool Predicate(<T>)
となっており、YesかNoかの判定に使われる。
List<T>の中で利用されているのは
.Exists
.Find
.FindAll
.FindIndex
.FindLast
.FindListIndex
.RemoveAll
.TrueForAll
と多用されている。
ちなみにArrayにも同様に採用されているので、単純な配列でも同様の処理が可能だ。
おまけの匿名メソッド版の場合には記述が離れた位置にならないため、よりわかりやすい記述になる。
private void button1_Click(object sender, EventArgs e)
{
List<string> ls = new List<string>();
ls.Add("1");
ls.Add("B");
ls.Add("3");
List<string> ls2 = ls.FindAll(delegate(string text)
{
try
{
int.Parse(text);
return true;
}
catch (FormatException)
{
return false;
}
});
}
連載をまとめてあります。
http://blogs.users.gr.jp/naka/category/285.aspx