LoginSignup
5
3

高速な検索をおこなうSearchValues<T>クラス

Last updated at Posted at 2024-03-26

参考

この記事は、以下の動画を参考にしています。詳しくは、動画をご覧ください。

また、リファレンスも参考にしてください。

SearchValue<T>

  • コレクションを引数にして、インスタンスを生成する
  • インスタンスに対してContainsメソッドを呼び、引数にした値が含まれているかどうかを戻す
  • .NET 8では、コレクションのデータ型はcharまたはbyteのみ
  • .NET 9では、加えてstringも可能
  • どのようにstringを比較するかは、インスタンスを生成するときに、StringComparisonを渡して、あらかじめ決める。Containsを呼ぶときにはStringComparisonを変更できない

訂正(追記)

参考にした動画に、訂正が入りました。

この記事も、訂正させていただきます。

Containsメソッドが本題ではない

SearchValues<T>.Containsメソッドは、SearchValues<T>を単にHashSet<T>として使っているだけである。実際にパフォーマンスは同等である。

長大な文字列から部分文字列を探す

長いstringに、特定の単語が含まれているかを調べたいとする。

string.Containsメソッドを使うと、次のようになる。

string longText = new HttpClient()
    .GetStringAsync("https://www.gutenberg.org/cache/epub/100/pg100.txt")
    .GetAwaiter()
    .GetResult();
var targetWords = ["target", "words"];

var found = targetWords.Any(x => longText.Contains(x, StringComparison.OrdinalIgnoreCase);
// foundがtrueなら、targetWordsのいずれかを見つけた

SearchValues<string>を引数にするContainsAny拡張メソッドを使うと、以下のように記述できる。

ReadOnlySpan<char> longText = new HttpClient()
    .GetStringAsync("https://www.gutenberg.org/cache/epub/100/pg100.txt")
    .GetAwaiter()
    .GetResult();
var targetWords = SearchValues.Create(["target", "words"],
                                      StringComparison.OrdinalIgnoreCase);
var found = longText.ContainsAny(targetWords);
// foundがtrueなら、targetWordsのいずれかを見つけた

手元の実行環境では、後者は前者に比べて約半分の実行時間になった。

文字列に対してSearchValues<string>を引数にして呼び出せる拡張メソッド

以下の拡張メソッドが、System.MemoryExtensionsクラスで定義されている。(.NET 9 Preview 2時点)

  • ContainsAny
  • IndexOfAny

いずれのメソッドも、第1引数はSpan<char>またはReadOnlySpan<char>、第2引数はSearchValue<string>である。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3