プログラミングGeekなブログ。

日々プログラミングしていて気づいたことのメモ。たまに音楽など。

C++のstd::binary_searchで構造体を検索&イテレーターを取得

ソート済み構造体の配列を検索して、見つかった位置のイテレーターを取得するというネタです。
タイトルにはstd::binary_searchとありますけど、binary_searchでは見つかった位置は 分からないので、std::lower_boundを使用します。 定番ですけど、いざやろうとするとパッと出てこないので、備忘録も兼ねて。。

検索する関数
#include <algorithm>

template <class ForwardIterator, class T, class Compare>
ForwardIterator bfind(ForwardIterator first, ForwardIterator last, const T &val,
                      Compare comp) {
  ForwardIterator it = std::lower_bound(first, last, val, comp);

  if (it != last && !comp(val, *it)) {
    return it;
  } else {
    return last;
  }
}

構造体などのデータ配列を検索するので、比較関数compも指定してやります。

サンプル
#include <algorithm>
#include <tuple>
#include <vector>

int main() {
  using Data = std::tuple<int, std::string>;
  std::vector<Data> data{
      {4, "a"}, {2, "b"}, {1, "d"},
  };
  auto comp_first = [](const Data &lhs, const Data &rhs) {
    return std::get<0>(lhs) < std::get<0>(rhs);
  };
  auto comp_second = [](const Data &lhs, const Data &rhs) {
    return std::get<1>(lhs) < std::get<1>(rhs);
  };

  auto it = bfind(data.begin(), data.end(), Data{0, "b"}, comp_second);
  if (it != data.end()) {
    std::cout << "Data={" << std::get<0>(*it) << ", "
              << std::get<1>(*it).c_str() << "}" << std::endl;
  }
  it = bfind(data.begin(), data.end(), Data{0, "c"}, comp_second);
  if (it == data.end()) {
    std::cout << "Not found" << std::endl;
  }

  std::sort(data.begin(), data.end());
  it = bfind(data.begin(), data.end(), Data{4, ""}, comp_first);
  if (it != data.end()) {
    std::cout << "Data={" << std::get<0>(*it) << ", "
              << std::get<1>(*it).c_str() << "}" << std::endl;
  }
  it = bfind(data.begin(), data.end(), Data{3, ""}, comp_first);
  if (it == data.end()) {
    std::cout << "Not found" << std::endl;
  }

  return 0;
}
実行結果
Data={2, b}
Not found
Data={4, a}
Not found

簡単ですね。