怠惰にコンテナを処理する

　[C++ Streams](http://jscheiny.github.io/Streams/) というライブラリがあります。これは、平たく言うとコンテナに対する処理を提供するもので、標準の汎用アルゴリズム、Boost.Range、PStade.Oven などの競合に当たります。

　ワードカウントやります。始めは、標準のアルゴリズムを使います。

```cpp
#include <algorithm>
#include <iostream>
#include <regex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

int main() {
  auto sentence = std::string("You play with the cards you're dealt... whatever that means.");

  sentence = std::regex_replace(sentence, std::regex("[^a-zA-Z]"), "");
  std::transform(sentence.begin(), sentence.end(), sentence.begin(), ::toupper);

  const auto counts =
    std::accumulate(sentence.begin(), sentence.end(), std::unordered_map<char, int>(), [](auto counts, auto word) {
      counts.insert(std::make_pair(word, ++counts[word]));
      return counts;
    });

  auto result = std::vector<std::pair<char, int>>(counts.begin(), counts.end());
  std::sort(result.begin(), result.end(), [](auto a, auto b) {
    return b.second < a.second;
  });
  std::for_each(result.begin(), result.end(), [](auto pair) {
    std::cout << pair.first << ": " << pair.second << std::endl;
  });
}
```

次に、脱アルゴリズム宣言します。

```cpp
#include <iostream>
#include <regex>
#include <string>
#include <unordered_map>
#include <utility>

#include "Stream.h"

int main() {
  using streams = stream::MakeStream;

  const auto sentence = std::string("You play with the cards you're dealt... whatever that means.");

  const auto counts =
    streams::from(std::regex_replace(sentence, std::regex("[^a-zA-Z]"), ""))
    .map(::toupper)
    .reduce(std::unordered_map<char, int>(), [](auto counts, auto word) {
      counts.insert(std::make_pair(word, ++counts[word]));
      return counts;
    });

  streams::from(counts).sort([](auto a, auto b) {
    return b.second < a.second;
  })
  .for_each([](auto pair) {
    std::cout << pair.first << ": " << pair.second << std::endl;
  });
}
```

　唐突ですけど、C++ Streams と Boost.Asio と標準の正規表現を使ってみたかったので、ウェブスクレイピングやります。

```cpp
#include <iostream>
#include <regex>
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/format.hpp>

#include "Stream.h"

int main() {
  using streams = stream::MakeStream;

  const auto source =
    streams::range(0, 3).reduce(std::string(), [](std::string source, int offset) {
      boost::asio::ip::tcp::iostream stream("cpplover.blogspot.jp", "http");
      stream << boost::format("GET /search?q=pdf&start=%d HTTP/1.0\r\n") % (offset * 20)
             << "Host: cpplover.blogspot.jp\r\n\r\n"
             << std::flush;

      for (std::string line; std::getline(stream, line); ) {
        source += line;
      }

      return source;
    });

  const auto re = std::regex("\\.pdf\">\\[(.+?)\\]");
  const auto begin = std::sregex_iterator(source.begin(), source.end(), re);
  const auto end = std::sregex_iterator();
  streams::from(begin, end).for_each([](auto s) {
    std::cout << s[1].str() << std::endl;
  });
}
```

```sh
$ g++ main.cpp -std=c++14 -lboost_system -I ./Streams/source/
```

楽しい！ ✌(’ω’✌ )三✌(’ω’)✌三( ✌’ω’)✌

> [jscheiny/Streams - GitHub](https://github.com/jscheiny/Streams)

> [Boost.Asio - boost C++ Libraries](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio.html)

> [&lt;regex&gt; - C++ Reference](http://www.cplusplus.com/reference/regex/)