web-dev-qa-db-ja.com

ベクトルの内容を印刷する方法

C++でベクトルの内容を印刷したいのですが、これは私が持っているものです:

#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <vector>
#include <sstream>
#include <cstdio>
using namespace std;

int main()
{
    ifstream file("maze.txt");
    if (file) {
        vector<char> vec(istreambuf_iterator<char>(file), (istreambuf_iterator<char>()));
        vector<char> path;
        int x = 17;
        char entrance = vec.at(16);
        char firstsquare = vec.at(x);
        if (entrance == 'S') { 
            path.Push_back(entrance); 
        }
        for (x = 17; isalpha(firstsquare); x++) {
            path.Push_back(firstsquare);
        }
        for (int i = 0; i < path.size(); i++) {
            cout << path[i] << " ";
        }
        cout << endl;
        return 0;
    }
}

ベクトルの内容を画面に印刷する方法

230
forthewinwin

純粋にあなたの質問に答えるために、イテレータを使用できます:

std::vector<char> path;
// ...
for (std::vector<char>::const_iterator i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

Forループでベクターのコンテンツを変更する場合は、const_iteratorではなくiteratorを使用します。

しかし、これについて言えることは他にもたくさんあります。使用できる答えだけが必要な場合は、ここで停止できます。それ以外の場合は、読んでください。

auto(C++ 11)/ typedef

これは別のソリューションではありませんが、上記のiteratorソリューションの補足です。 C++ 11標準(またはそれ以降)を使用している場合は、autoキーワードを使用して読みやすくすることができます。

for (auto i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

ただし、iの型は非定数です(つまり、コンパイラはiの型としてstd::vector<char>::iteratorを使用します)。

この場合は、typedefを使用することもできます(C++ 11に限定されず、veryとにかく便利です) :

typedef std::vector<char> Path;
Path path;
// ...
for (Path::const_iterator i = path.begin(); i != path.end(); ++i)
    std::cout << *i << ' ';

カウンタ

もちろん、整数型を使用してforループ内の位置を記録できます。

for(int i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';

これを行う場合、コンテナのメンバータイプが使用可能で適切であれば、それを使用することをお勧めします。 std::vectorには、このジョブのsize_typeというメンバータイプがあります。これは、sizeメソッドによって返されるタイプです。

// Path typedef'd to std::vector<char>
for( Path::size_type i=0; i<path.size(); ++i)
  std::cout << path[i] << ' ';

これをiteratorソリューションで使用しないのはなぜですか?単純な場合でも同様ですが、ポイントはiteratorクラスが、このソリューションが理想的ではないより複雑なオブジェクトに対してこのジョブを実行するように設計されたオブジェクトであるということです。

範囲ベースのforループ(C++ 11)

Jefffreyの解 を参照してください。 C++ 11(以降)では、次のような新しい範囲ベースのforループを使用できます。

for (auto i: path)
  std::cout << i << ' ';

pathはアイテムのベクター(明示的にstd::vector<char>)であるため、オブジェクトiはベクターのアイテムのタイプです(つまり、明示的にcharタイプです)。オブジェクトiの値は、pathオブジェクト内の実際のアイテムのコピーです。したがって、ループ内のiへのすべての変更は、path自体に保存されません。さらに、ループ内のiのコピーされた値を変更したくないという事実を強制したい場合、iのタイプをconst charに強制することができます:

for (const auto i: path)
  std::cout << i << ' ';

pathのアイテムを変更する場合は、参照を使用できます。

for (auto& i: path)
  std::cout << i << ' ';

pathを変更したくない場合でも、オブジェクトのコピーが高価な場合は、値でコピーする代わりにconst参照を使用する必要があります。

for (const auto& i: path)
  std::cout << i << ' ';

std :: copy

ジョシュアの答え を参照してください。 STLアルゴリズムstd::copyを使用して、ベクターコンテンツを出力ストリームにコピーできます。これは、慣れている場合はエレガントなソリューションです(さらに、ベクトルの内容を印刷する場合だけでなく、very便利です) )。

std :: for_each

Maxの解 を参照してください。 std::for_eachの使用はこの単純なシナリオでは過剰ですが、スクリーンに印刷するだけでなく、それ以外のことをしたい場合には非常に便利なソリューションです。std::for_eachを使用すると、 any (賢明な)操作ベクトルの内容。

オーバーロードostream :: operator <<

Chris's answer を参照してください。これは、オーバーロードで上記のソリューションのいずれかを実装する必要があるため、他の回答を補完するものです。彼の例では、彼はforループでカウンターを使用しました。たとえば、これは Joshuaのソリューション をすばやく使用する方法です。

template <typename T>
std::ostream& operator<< (std::ostream& out, const std::vector<T>& v) {
  if ( !v.empty() ) {
    out << '[';
    std::copy (v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
    out << "\b\b]";
  }
  return out;
}

他のソリューションの使用方法は簡単です。

結論

ここに示されているソリューションはどれでも機能します。それはあなたと、それが「最良」であるコード次第です。これよりも詳細な点は、賛否両論を適切に評価できる別の質問に残しておくとよいでしょう。しかし、いつものように、ユーザーの好みは常に役割を果たします。提示された解決策はどれも間違っていませんが、個々のコーダーにとってより見栄えの良いものもあります。

補遺

これは、以前に投稿したソリューションを拡張したソリューションです。その投稿が注目を集めていたので、私はそれを拡張し、ここに投稿された他の優れたソリューションを参照することにしました。私の元の投稿には、 were を[forループ内でベクトルを変更する場合、要素にアクセスするstd::vectorによって提供される2つのメソッドがあります:std::vector::operator[]境界チェックを行いません。std::vector::atは境界チェックを行います。つまり、ベクトルの外部の要素にアクセスしようとしてもoperator[]がアクセスしない場合、atはスローされます。元々このコメントを追加したのは、誰かが既に知らなかった場合に知っておくと役立つかもしれないことを言及するためです。そして今、私は違いが見られません。したがって、この補遺。

337
Zorawar

もっと簡単な方法は、標準の コピーアルゴリズムを使うことです

#include <iostream>
#include <algorithm> // for copy
#include <iterator> // for ostream_iterator
#include <vector>

int main() {
    /* Set up vector to hold chars a-z */
    std::vector<char> path;
    for (int ch = 'a'; ch <= 'z'; ++ch)
        path.Push_back(ch);

    /* Print path vector to console */
    std::copy(path.begin(), path.end(), std::ostream_iterator<char>(std::cout, " "));

    return 0;
}

Ostream_iteratorはiterator adapterと呼ばれるものです。それはストリームに出力するために型をテンプレート化したものです(この場合はchar)。 cout(別名コンソール出力)は書き込みたいストリームで、スペース文字(" ")はベクトルに格納された各要素の間に表示したいものです。

この標準アルゴリズムは強力で、他にもたくさんあります。標準ライブラリがあなたに与える力と柔軟性はそれをそれほど素晴らしいものにします。想像してみてください。 one のコード行でベクトルをコンソールに表示できます。区切り文字を使って特別な場合を扱う必要はありません。 forループについて心配する必要はありません。標準ライブラリはあなたのためにそれをすべて行います。

197
Joshua Kravitz

C++ 11では、 範囲ベースのforループ :を使用できます。

for (auto const& c : path)
    std::cout << c << ' ';
64
Shoe

これを行う最良の方法は、この関数をプログラムに追加してoperator<<をオーバーロードすることです。

#include <vector>
using std::vector;
#include <iostream>
using std::ostream;

template<typename T>
ostream& operator<< (ostream& out, const vector<T>& v) {
    out << "{";
    size_t last = v.size() - 1;
    for(size_t i = 0; i < v.size(); ++i) {
        out << v[i];
        if (i != last) 
            out << ", ";
    }
    out << "}";
    return out;
}

その場合、その要素にも<<が定義されていると仮定すれば、可能性のあるすべてのベクトルに対してostream& operator<<演算子を使用できます。

vector<string>  s = {"first", "second", "third"};
vector<bool>    b = {true, false, true, false, false};
vector<int>     i = {1, 2, 3, 4};
cout << s << endl;
cout << b << endl;
cout << i << endl;

出力:

{first, second, third}
{1, 0, 1, 0, 0}
{1, 2, 3, 4}
37
Chris Redford

どうですかfor_each +ラムダ式

#include <vector>
#include <algorithm>
...
std::vector<char> vec;
...
std::for_each(
              vec.cbegin(),
              vec.cend(),
              [] (const char c) {std::cout << c << " ";} 
              );
...

もちろん、 の範囲ベースの はこの具体的な作業のための最も洗練された解決策ですが、これも他の多くの可能性を与えます。

説明

for_eachアルゴリズムは 入力範囲 呼び出し可能オブジェクト を取り、このオブジェクトを範囲のすべての要素で呼び出します。 入力範囲 は、2つの イテレータ によって定義されます。 呼び出し可能オブジェクト は、関数、関数へのポインタ、() operatorをオーバーロードするクラスのオブジェクト、またはこの場合のように ラムダ式 のいずれかです。この式のパラメータはvectorの要素の型と一致します。

この実装の利点は、ラムダ式から得られるパワーです。ベクトルを印刷するだけでなく、このアプローチをもっと多くのことに使用できます。

18
Maxim Chetrusca

コンテナーをコンソールにコピーするだけです。

std::vector<int> v{1,2,3,4};
std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout, " " ));

出力する必要があります:

1 2 3 4
8
g24l

問題はおそらく前のループにあります:(x = 17; isalpha(firstsquare); x++)。このループはまったく実行されず(firstsquareが非アルファの場合)、または永久に実行されます(アルファの場合)。その理由は、firstsquareが増加してもxは変化しないからです。

8
MSalters

C++ 11では、範囲ベースのforループが良い解決策かもしれません。

vector<char> items = {'a','b','c'};
for (char n : items)
    cout << n << ' ';

出力:

a b c 
5

std::copyを使用しますが、追加の末尾の区切り記号は使用しません

std::copy を使用する( @JoshuaKravtiz answer で最初に使用されていた)代替の/変更されたアプローチ。

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

template <typename T>
void print_contents(const std::vector<T>& v, const char * const separator = " ")
{
    if(!v.empty())
    {
        std::copy(v.begin(),
                  --v.end(),
                  std::ostream_iterator<T>(std::cout, separator));
        std::cout << v.back() << "\n";
    }
}

// example usage
int main() {
    std::vector<int> v{1, 2, 3, 4};
    print_contents(v);      // '1 2 3 4'
    print_contents(v, ":"); // '1:2:3:4'
    v = {};
    print_contents(v);      // ... no std::cout
    v = {1};
    print_contents(v);      // '1'
    return 0;
}

カスタムPODタイプのコンテナに適用される使用例

// includes and 'print_contents(...)' as above ...

class Foo
{
    int i;
    friend std::ostream& operator<<(std::ostream& out, const Foo& obj);
public:
    Foo(const int i) : i(i) {}
};

std::ostream& operator<<(std::ostream& out, const Foo& obj)
{
    return out << "foo_" << obj.i; 
}

int main() {
    std::vector<Foo> v{1, 2, 3, 4};
    print_contents(v);      // 'foo_1 foo_2 foo_3 foo_4'
    print_contents(v, ":"); // 'foo_1:foo_2:foo_3:foo_4'
    v = {};
    print_contents(v);      // ... no std::cout
    v = {1};
    print_contents(v);      // 'foo_1'
    return 0;
}
3
dfri

オーバーロード演算子<<:

template<typename OutStream, typename T>
OutStream& operator<< (OutStream& out, const vector<T>& v)
{
    for (auto const& tmp : v)
        out << tmp << " ";
    out << endl;
    return out;
}

使用法:

vector <int> test {1,2,3};
wcout << test; // or any output stream
3
ivanmara

2つ問題があります。 for (x = 17; isalpha(firstsquare); x++)で指摘されているように、無限ループがあるかまったく実行されないか、またif (entrance == 'S')では入口文字が 'S'と異なる場合は何もパスベクトルにプッシュされず、空になり画面に何も表示しません。後者のpath.empty()のチェックやpath.size()の出力をテストすることができます。

どちらの方法でも、ベクトルの代わりに文字列を使用するほうが良いでしょうか。配列のように文字列の内容にアクセスしたり、文字を探したり、部分文字列を抽出したり、文字列を簡単に印刷したりできます(ループなし)。

すべて文字列でそれを行うことは、それを複雑でない方法で書いて問題を見つけやすくするための方法かもしれません。

3
miguelbernadi

この回答はZorawarの回答に基づいていますが、私はそこにコメントを残すことができませんでした。

代わりにcbeginおよびcendを使用して、auto(C++ 11)/ typedefバージョンをconstにすることができます。

for (auto i = path.cbegin(); i != path.cend(); ++i)
    std::cout << *i << ' ';
3
SketchyManDan

C++ 11では

for (auto i = path.begin(); i != path.end(); ++i)
std::cout << *i << ' ';

for(int i=0; i<path.size(); ++i)
std::cout << path[i] << ' ';
1
Akash Kandpal

これは私のために働いた:

    for (auto& i : name)
    {
    int r = 0;
    for (int j = 0; j < name[r].size();j++) 
    {
    std::cout << i[j];
    }
    r++;
    std::cout << std::endl;
    }
0
Tempi Skat
#include<bits/stdc++.h>
using namespace std;

int main()
{
    vector <pair<string,int> > v;
    int n;
    cin>>n;
int i;
    for( i=0;i<n;i++)
    {
        int  end;
        string str;
        cin>>str;
        cin>>end;
        v.Push_back(make_pair(str,end));
    }



for (int j=0;j<n;j++)
{
    cout<<v[j].first<< " "<<v[j].second<<endl;
}``
}
0
Bishal B Sonar

あなたはあなた自身の関数を書くことができます:

void printVec(vector<char> vec){
    for(int i = 0; i < vec.size(); i++){
        cout << vec[i] << " ";
    }
    cout << endl;
}
0
dolev ben

興味のある人のために:私は両方の長所を活用し、あらゆるタイプの範囲により一般化され、非算術タイプ(文字列のようなタイプに望ましい)を引用符で囲む一般化されたソリューションを書きました。さらに、このアプローチにはADLの問題はなく、「サプライズ」も回避する必要があります(ケースバイケースで明示的に追加されるため)。

template <typename T>
inline constexpr bool is_string_type_v = std::is_convertible_v<const T&, std::string_view>;

template<class T>
struct range_out {
  range_out(T& range) : r_(range) {
  }
  T& r_;
  static_assert(!::is_string_type_v<T>, "strings and string-like types should use operator << directly");
};

template <typename T>
std::ostream& operator<< (std::ostream& out, range_out<T>& range) {
  constexpr bool is_string_like = is_string_type_v<T::value_type>;
  constexpr std::string_view sep{ is_string_like ? "', '" : ", " };

  if (!range.r_.empty()) {
    out << (is_string_like ? "['" : "[");
    out << *range.r_.begin();
    for (auto it = range.r_.begin() + 1; it != range.r_.end(); ++it) {
      out << sep << *it;
    }
    out << (is_string_like ? "']" : "]");
  }
  else {
    out << "[]";
  }

  return out;
}

これで、どの範囲でもかなり簡単に使用できます。

std::cout << range_out{ my_vector };

文字列のようなチェックには改善の余地があります。 static_assertを回避するためにstd::basic_string<>チェックインもしていますが、簡単にするためにここでは省略しました。

0
darune