Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

std::max_element, std::min_element

min_element, max_element は,最小値,最大値のイテレータを返してくれる関数.

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 と組み合わせればうまいこと取得できる.

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 を使えば一発でできる.

#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

#include <algorithm>

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

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

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

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 のような浅いコピー系であるとき,全要素に関して深いコピーにしたいとき,次の様にできる,意味的に少し合わないので使わない方が無難か?

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 と組み合わせて相当変態なコードができる.

//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 に限らずランダムイテレーターであれば何でもいける.

#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;
}
myVector = [10, 20, 30, 40, 50, 60, 70, 80, 90]
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした