1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【C++】配列から条件に合う値をfilterするいい方法は「小さいテンプレートメソッドを自作する」です

Posted at

C++で配列から条件に合う値をfilterするいい方法は?

ちなみにRuby

[1,2,3,4,5].select {|i| i.odd?} # -> [1,3,5]
['a','ab','c'].filter {|str| str.include?('a')} #->["a","ab"]

かなり直感的。できればこう書きたい。

ここまでとはいわないのでもう少し便利に汎用的なものがほしい!
それを探して、StatckOverflowの「Modern way to filter STL container?」スレッドでみつけた方法が便利だったので紹介します。

テンプレート関数をうまく利用したfilterを自作

コンテナと条件は引数で指定する形で、このメソッドひとつ定義しておけばコンテナの型はなんでもいいので汎用性が高いです。


template <typename Cont, typename Pred>
Cont filter(const Cont &container, Pred predicate) {
	Cont result;
	std::copy_if(container.begin(), container.end(), std::back_inserter(result), predicate);
	return result;
}

つかいかた:サンプルコード

# include <iostream>
# include <vector>
# include <algorithm>

template <typename Cont, typename Pred>
Cont filter(const Cont &container, Pred predicate) {
	Cont result;
	std::copy_if(container.begin(), container.end(), std::back_inserter(result), predicate);
	return result;
}

int main()
{
  // --------------------------
  // 「整数配列から偶数のみを取る」
  std::vector<int> numbers{ 1, 2, 3, 4, 5, 6 };
  const auto odd = filter(numbers, [](int a) { return a % 2 == 0; });

  for (auto& n : odd) {
    std::cout << n << std::endl;
    // 2, 4, 6
  }

  // --------------------------
  // 「どのビットが立っているかを調べる」
  const unsigned long expect_value = 0x23;
  std::vector<unsigned long> bits = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20 };

  const auto matched_bits = filter(flags, [](unsigned long bit) { return expect_value & bit; });

  for (auto& v : matched_bits) {
    std::cout << std::hex << v << std::endl;
    // 1, 2, 20 (hex表記)
  }

  // --------------------------
  // 「30歳以上の名前を集める」
  struct Person
  {
    std::string Name = "";
    int Age = 0;
  };
  std::vector<Person> people = {
    { "ueki", 35 },
    { "yamada", 20 },
    { "suzuki", 50 },
    { "saito", 19 },
  };
  const auto people_30_plus = filter(people, [](Person person) { return person.Age > 30; });
  
  for (auto& person : people_30_plus) {
    std::cout << person.Name.c_str() << std::endl;
	// "ueki", "suzuki"
  }
}

まとめ

  • 汎用性のあるテンプレートメソッドがあると、たくさんのメソッドをつくらずに済む
  • forループで回して値をチェック」より説明的でコードリーディングのとき脳への負担が軽い
  • 他のロジック(map,redudce)にも応用ができる
1
2
2

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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?