[c++]イテレータは怖くない

アバター
purin52002
記事: 235
登録日時: 7年前
連絡を取る:

[c++]イテレータは怖くない

投稿記事 by purin52002 » 7年前

よく考えてみれば平日の昼間っからプラプラできる人種なんて限られてるわけで。
そうすると、質問の回答なんて返ってくるわけもなくて。

、、、プログラム組むか^p^

の前に、最近私のお気に入りの関数をいくつか紹介。
[hr]
  • accumulate
    コンテナの中身を足し算
  • transform
    コンテナの中身にある処理をしてほかのコンテナに移す
  • for_each
    コンテナの中身に関数を使う。
algorithmライブラリの中にある関数たちです。(accumulateだけnumeric)
配列系を使うならalgorithmインクルードする。それぐらい便利です。

ただ、引数にイテレータを指定します。
c++始めたばかりだとイテレータって怖いと思います。(私は怖かったです^^;)
でも大丈夫、実はイテレータって何も怖くない。
正確には関数の引数に渡す分には何も怖くない。

accumulateを例にして考えてみましょう。
accumulateは簡単に言えばコンテナの中身の総和を返す関数です。

CODE:

int Sum(int x[10])
{
    int sum=0;
    for(int i=0;i
int main()
{
    int x[10]={1,2,3,4,5,6,7,8,9,10};
    int sum=std::accumulate(begin(x),end(x),0);//55

return 0;
}
どうです?すっきりしたでしょう?
え?全然してない?
それはおそらく見慣れない文字がたくさんあるからだと思います。
  • std::
  • begin(x)
  • end(x)
たぶんこいつらのせいです。
しかし安心してください。
意味が分かれば怖くありません。
  • std::
    「std」という名前空間にあるよ、というサイン。
    名前空間ってなんだよ?という方、教えません^^
    mainの最初に「using namespace std;」というおまじないを書いてください。
    std::をつけずにaccumulateと書けます。
  • begin(x)
    xの一番最初のイテレータを返す関数。
    イテレータってなんだよ?という方、教えません^^
    おまじないだと思って書いてください。
  • end(x)
    xの一番最後のイテレータを返す関数。
    イテレータってなんだよ?という方、教えません^^
    おまじないだと思って書いてください。
おまじないばっかりかよ!と思ったそこのあなた。
いいんです。最初のうちは機械的に手を動かしてください。

いずれ自分で少し大きなプログラムを作るときに、
「名前空間すげえ!名前空間さえ違ったら同じ名前の関数いくらでも作れる!」
となりますし、
いずれ自分で配列の一部にだけalgorithmを使いたくなった時に
「イテレータってポインタみたいなもんなんだなー」
となります。

知識っていうのはその知識を本当に必要としたときに得られるものです。
意味が分からないよ、って間はおまじないとして書いてください。

それではそれぞれの関数について、例題を示しながらプログラムを書いてみましょう。

accumulate
[codeaccumulate]
#include
#include

int main()
{
using namespace std;

int x[5]={1,3,5,7,9};
vector y={2,4,6,8,10};

int sum_x=accumulate(begin(x),end(x),0);//25

//注意!3番目の引数が返り値の型になります!
//doubleの数値がほしいなら0.0と書いてください。じゃないと悲しみが起きます^p^
double sum_y=accumulate(begin(y),end(y),0.0);//30.0

return 0;
[/code]

transform
[codetransform]
#include
#include

int func_x(int x_value)//適用する関数
{
return x_value+1;
}

double func_y(int x_value,double y_value)//適用する関数
{
return x_value*y_value;
}

int main()
{
using namespace std;

int x[5]={1,3,5,7,9};
vector y={2,4,6,8,10};

//格納先の配列は元の配列以上のサイズ
int tr_x[5];
vector tr_y(5);

//1,2の引数は元の配列の最初と最後のイテレータ、
//3の引数は新しく格納する配列の最初のイテレータ、
//4の引数は適用する関数の名前
transform(begin(x),end(x),begin(tr_x),func_x);//tr_x={2,4,6,8,10}

//2つの配列から新しい配列を作ることも可能

//1,2の引数は元の配列(1)の最初と最後のイテレータ、
//3の引数はは元の配列(2)の最初のイテレータ、
//4の引数は格納先の配列の最初のイテレータ
//5の引数は適用する関数の名前
//注意!元の配列が1つだけなら関数の引数は一つ、元の配列が2つなら関数の引数も二つになります。
//あと引数の型は配列の中身の型で、返り値の型は格納先の配列の中身の型になります。
transform(begin(x),end(x),begin(y),begin(tr_y),func_y);//tr_y={2,12,30,56,90}

return 0;
[/code]

for_each
[codetransform]
#include
#include

using namespace std;

void func(int x_value)//適用する関数
{
cout<<x_value<<",";
}

int main()
{
int x[5]={1,3,5,7,9};

for_each(begin(x),end(x),func);
cout<<endl;//コンソールに1,3,5,7,9,と出力
return 0;
[/code]

わかったことがあります。
3つも例題書くと疲れる^p^

っていうことで次回の例題は一つだけ、
今回for_eachで配列の中身を表示しましたが、ほかの関数を使えばさらに簡単に表示できます。

次回、copyってコピーじゃないのか?
続く、、、かな?

アバター
usao
記事: 1887
登録日時: 11年前

Re: [c++]イテレータは怖くない

投稿記事 by usao » 7年前

>よく考えてみれば平日の昼間っからプラプラできる人種なんて限られてるわけで。
>そうすると、質問の回答なんて返ってくるわけもなくて。

ククク…
仕事に行き詰ってうっかり掲示板とか覗いちゃう輩もいるのですよ…

まずい.仕事しないとまずい.
つらい.たまらなくつらい.

アバター
purin52002
記事: 235
登録日時: 7年前
連絡を取る:

Re: [c++]イテレータは怖くない

投稿記事 by purin52002 » 7年前

そういう輩、大歓迎です^^
どんどん仕事に行き詰ってくださいねw

アバター
usao
記事: 1887
登録日時: 11年前

Re: [c++]イテレータは怖くない

投稿記事 by usao » 7年前

3つともほぼ使ったことない気がする……


>accumulate
「そんなものがあったのか…」という.(とかいうのをまず使ったことない気がする私.)
一見使えそうに見えるけど,よく考えると使う機会なさそう…?


>transform
私くらいの雑魚は使わない方が賢明.
背伸びしてこういうのを使うと,後から読むとき(=どっかにバグがあるときだ)「transformって引数どんなだっけ…?」とかなる.
自分で後から読めないだけならまだしも(?),環境次第では周りからも「普通に書けやクソが」と激しく責められるので注意が必要.これが現実.


>for_each
範囲forが無かった時代ですら使うことはなかった.
・内側に処理分岐だの戻り値使ってどうのだのbreakとかcontinueとかいう諸々が一切無いforとかまず書かない
・処理範囲が事前に既知ということもあまりない

アバター
purin52002
記事: 235
登録日時: 7年前
連絡を取る:

Re: [c++]イテレータは怖くない

投稿記事 by purin52002 » 7年前

共同開発する場合とかは全員関数の挙動について知らないとまずいですね^^;

コンテナ扱う系の関数は基本的に中身全部forで書いてあるみたいです。
for文ばっか書いてんな、って思ったときにふと思い出していただければ幸いです^^