忘れがちな C++ の標準ライブラリの使い方


実は，C++ 標準ライブラリで基本的なアルゴリズムは用意されている．案外これが知られてなかったり忘れられてたりするのでメモしておく．

# std::max_element, std::min_element
min_element, max_element は，最小値，最大値のイテレータを返してくれる関数．

```cpp
std::vector<int> vec(100);
for (size_t i = 0; i < vec.size(); ++i) {
    vec[i] = i;
}

std::random_shuffle (vec.begin(), vec.end());

// std::*_element は，イテレーターを返すので '*' で値を取得する
int min = *std::min_element(vec.begin(), vec.end());
int max = *std::max_element(vec.begin(), vec.end());
```

とこのようにイテレーターを取得するすることができる．ここで，最大値と最小値の添え字を取得したい場合も多いその場合は，`std::distance` と組み合わせればうまいこと取得できる．

```cpp
std::vector<int>::iterator minIt = *std::min_element(vec.begin(), vec.end());
std::vector<int>::iterator maxIt = *std::max_element(vec.begin(), vec.end());

// distance で vec の先頭イテレーターと minIt, maxIt との距離を取得する．
// インデックスを取得したいときは，vec の先頭イテレーターを指定する必要がある．
// 例えば，vec.begin() + 1 とか指定すると答えは変わる．
size_t minIndex = std::distance(vec.begin(), minIt);
size_t maxIndex = std::distance(vec.begin(), maxIt);
```


# std::accumulate
総和を自分で実装している人は多いのでは，accumulate を使えば一発でできる．

```cpp
#include <numeric>

int main() 
{
    int list[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    const size_t size = sizeof(list) / sizeof(list[0]);
    
    int sum = std::accumulate(list, list + size, 0);    // ans = 55
    return 0;
}
```



# std::transform
A から B へ変換するといったときに使う．よく出る事例は，全て小文字にする `tolower` と全てを大文字にする `toupper`

```cpp
#include <algorithm>

std::string src ="abc";
std::string dst = src;

// src と dst のサイズが同じでなければダメ．
std::transform(src.begin(), src.end(), dst.begin(), toupper);
```

何をしているのか．単に，src と dst に関してループを回して toupper を適応しているだけ．ちょっとわかりやすく書くと? 以下の様になる．

```cpp
std::string::const_iterator it = src.begin();    // 入力用のイテレーター
std::string::iterator result = dst.begin();      // 結果用のイテレーター
while (it != src.end()) {
    *result = toupper(*it);    // 一文字ずつ toupper を適応して result に入れる
    ++it;        // 入力用イテレーターを進める
    ++result;    // 出力用のイテレーターを進める
}
```

ここで，toupper に値する関数が好きに指定できることが特徴．

だから，例えば，コンテナの要素が cv::Mat のような浅いコピー系であるとき，全要素に関して深いコピーにしたいとき，次の様にできる，意味的に少し合わないので使わない方が無難か?

```cpp
cv::Mat toCopyDeep(const cv::Mat &src)
{
    return src.clone();
}

std::vector<cv::Mat> src;
std::vector<cv::Mat> dst(src.size());
std::transform(src.begin(), src.end(), dst.begin(), toCopyDeep);
```


# std::copy
std::iostream と組み合わせて相当変態なコードができる．

```cpp
//http://www.cplusplus.com/reference/iterator/ostream_iterator/
#include <iostream>     // std::cout
#include <iterator>     // std::ostream_iterator
#include <vector>       // std::vector
#include <algorithm>    // std::copy

int main () {
    // vector の初期化 10-90 の代入
    std::vector<int> myvector;
    for (int i=1; i<10; ++i) {
        myvector.push_back(i*10);
    }
    
    std::ostream_iterator<int> out_it (std::cout,", ");
    std::copy(myvector.begin(), myvector.end(), out_it );    // ? 一瞬理解できない ?
    return 0;
}
```


結果

```
10, 20, 30, 40, 50, 60, 70, 80, 90, 
```

これを使えばあっさりと以下の様なvectorの中身を表示する関数を作れる．vector に限らずランダムイテレーターであれば何でもいける．

```cpp
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

template <typename T>
std::string printVector(const std::vector<T> &data)
{
    std::stringstream ss;
    std::ostream_iterator<T> out_it(ss, ", ");
    ss << "[";
    std::copy(data.begin(), data.end() - 1, out_it);
    ss << data.back() << "]";
    return ss.str();
}


int main() {
    // vector の初期化 10-90 の代入
    std::vector<int> myvector;
    for (int i = 1; i<10; ++i) {
        myvector.push_back(i * 10);
    }

    std::cout << "myVector = " << printVector(myvector) << std::endl;
    return 0;
}
```


```cpp
myVector = [10, 20, 30, 40, 50, 60, 70, 80, 90]
```