I'm making a function which prints the elements of a std::vector<float>.
Working code:
std::vector<float> components { 1, 2, 3 };
string result = "<";
for ( auto it = begin(this->components); it != end(this->components); ++it ) {
result.append(to_string(*it));
if (it != (this->components))
result.append(", ");
}
result.append(">");
std::cout << result;
The intended result is if "components" has elements 1,2,3, for example, it will print: <1, 2, 3>.
Right now it is printing the numbers as floats, of course, like < 1.000000, 2.000000, 3.000000, >.
Is there a way I can control how many decimal places are put into the string, without having to manually go through it character by character?
As a side note, how do I prevent it from adding a ',' after the last element?
You may use std::stringstream.precision for that.
Just create a std::stringstream convert it to a string and your done.
Like so:
stringstream ss;
ss.precision(3);
ss << "<";
for ( auto it = begin(this->components); it != end(this->components); ++it ) {
ss << *it;
if (it != (this->components))
ss << ", ";
}
ss << ">";
string result = ss.str();
you can use sprintf() before casting:
float a = 1.000000;
char aa[20];
sprintf(aa, "%1.3f", a);
Here is the complete code which i ran:
#include <vector>
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
std::vector<float> components{ 1, 2, 3 };
string result = "<";
for (auto it = components.begin(); it != components.end(); ++it) {
float a = *it;
char aa[20];
sprintf(aa, "%1.3f", a);
result.append(string(aa));
if (it+1 != components.end())
result.append(", ");
}
result.append(">");
std::cout << result.c_str();
getchar();
return 0;
}
Output:
I would do it like this using a stringstream.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
int main()
{
std::vector<float> components {1, 2, 3, 1.5f, 2.5f, 3.5f, 1.25f, 2.25f, 3.25f, 1.12345f};
std::stringstream result;
result << "<";
for(auto it = std::begin(components); it != std::end(components); ++it)
{
if(it != std::begin(components))
{
result << ", ";
}
result << *it;
}
result << ">";
std::cout << result.str();
return 0;
}
You could also use std::fixed and std::setprecision to modify the output further as you desire.
Printing the comma before the next item for all but the first item fixes your trailing comma issue.
Here's a demo of it working:
As #Axalo already noted, you can use setprecision with an ostream to set its precision (and it can be used with any ostream, not just cout).
To eliminate the trailing comma, I'd probably use the infix iterator I've posted elsewhere.
Using that, the code could be written something like this:
#include <iostream>
#include <sstream>
#include <vector>
#include <iomanip>
#include "infix_iterator.h"
int main () {
// Data that would display extra precision if we didn't stop it
std::vector<float> components { 1.123f, 2.234f, 3.345f };
std::ostringstream buff("<", std::ios::app);
buff << std::setprecision(2);
std::copy(components.begin(), components.end(),
infix_ostream_iterator<float>(buff, ", "));
buff << ">";
std::cout << buff.str();
}
Result: <1.1, 2.2, 3.3>
Related
I've been trying to put every single element of a vector of integers into a string. I want to achieve this by type casting the integers into strings, after that I cocatenate those "small strings" into a single big string, which is going to represent all the elements of that specific vector.
This may look silly, but is really useful if you want to make a function that returns a vector like-a-thing, or etc.
The only problem is that I'm getting an error on line 13, which says :
error: no matching function for call to ‘std::__cxx11::basic_string<char>::basic_string(int&)’
13 | myString += (string) myVector[i];
| ^
and I don't have the slightest idea on why this is happening. My code follows below :
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int myVector[5] = {1,2,3,4,5};
string myString = "";
for (int i =0; i < 5; i++)
{
myString += (string) myVector[i];
myString += "\n";
}
cout << myString << endl;
any help will be much appreciated.
You can use std::to_string to convert an int to a std::string.
Change this line:
myString += (string) myVector[i];
To:
myString += std::to_string(myVector[i]);
Note: concatenating strings like that might not be so efficient due to temporary strings being created and destroyed (although it is likely that small strings optimization will kick in, so no additional heap allocations will take place).
As #Someprogrammerdude commented, you can consider to use std::ostringstream.
Side notes:
You are missing #include <string>.
Why is "using namespace std;" considered bad practice?.
You can use the fmt library:
fmt::join will accept a range, in your case a vector of ints, and join its contents with a given separator (e.g. an empty string if you just want all of the elements together).
fmt::format will create a string with a given format, in this case just the contents of the joined vector.
Demo
#include <fmt/ranges.h>
int main() {
int myVector[5] = {1,2,3,4,5};
auto myString = fmt::format("{}", fmt::join(myVector, ""));
fmt::print("{}\n", myString);
}
// Outputs: 12345
Or, simpler, if you don't need the string:
int main() {
int myVector[5] = {1,2,3,4,5};
fmt::print("{}\n", fmt::join(myVector, ""));
}
The error you are getting is saying that the compiler cannot find a std::__cxx11::basic_string<char>::basic_string(int&) function, i.e., a std::string constructor accepting an int&.
You can use std::stringstream
#include <iostream>
#include <string>
#include <sstream>
int main()
{
int myVector[5] = {1,2,3,4,5};
std::string myString;
std::stringstream sstream;
for (auto i : myVector)
sstream << i;
sstream >> myString;
std::cout << myString;
}
Link.
I'll add my own solution, as laid out in my comment:
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
int main()
{
std::vector myvector = { 1, 2, 3, 4, 5 };
std::copy(std::begin(myvector), std::end(myvector),
std::ostream_iterator<int>(std::cout, "\n"));
}
Overload the output stream operator, and then you have something reusable for a lot of scenarios.
Based on the feedback below overloading is not the best answer, another approach here : https://www.onlinegdb.com/zDUjVbSTp
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
// Overloading operator<< will have many benefits.
// you can use it to output an array to std::cout directly
// or you can write it to a file or stringstream
std::ostream& operator<<(std::ostream& os, const std::vector<int>& values)
{
os << "[";
bool comma = false;
for (const auto& value : values)
{
if (comma) os << ", ";
os << value;
comma = true;
}
os << "]";
return os;
}
int main()
{
std::vector<int> values{ 1,2,3,4,5 };
// write directly to std::cout
std::cout << "direct : " << values << "\n";
// adding array to a string
std::ostringstream os;
std::string string{ "output = " };
os << values;
string += os.str();
std::cout << string << "\n";
return 0;
}
You can use for_each algorithm as well to do the concatenation.
#include <iostream>
#include <algorithm>
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6};
std::string all;
std::for_each(v.begin(), v.end(), [&, del=""](const int &e) {
all += std::to_string(e) + (&e == &v.back() ? "" : del);
});
std::cout << all << std::endl;
}
output:
123456
If you want to add a delimiter in between, just change the del value in lambda capture.
std::for_each(v.begin(), v.end(), [&, del="-"](const int &e) {
all += std::to_string(e) + (&e == &v.back() ? "" : del);
});
Output:
1-2-3-4-5-6
double floaty=36.6736872;
cout<<fixed<<setprecision(10)<<floaty;
My output is "36.6736872000";
I want my zeros to be some other number.
Eg: If I want zeros to be ^.
then the output should be 36.6736872^^^
I don't have any idea other than using setw and setfill to get my desired output in single line of code
You can use std::ostringstream, and change the resulting string in any way you see fit:
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
int main()
{
double floaty=36.6736872;
std::ostringstream strm;
// Get the output as a string
strm << std::fixed << std::setprecision(10) << floaty;
std::string out = strm.str();
// Process the output
auto iter = out.rbegin();
while (iter != out.rend() && *iter == '0')
{
*iter = '^';
++iter;
}
std::cout << out;
}
Output:
36.6736872^^^
for (vector<int>::const_iterator i = vec.begin(); i != vec.end(); ++i)
{
int number = *i;
char* c;
itoa(number, c, 10);
result += c;
}
std::cout << result << std::endl;
I'm trying to convert each int in "vec" to a char and adding it to a string but I just get a compiler error. what am I doing wrong?
You can use the std::to_string available in C++11:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<int> vec;
for (int i = 0; i < 100; i++)
{
vec.push_back(i);
}
std::string result;
for (std::vector<int>::const_iterator i = vec.begin(); i != vec.end(); ++i)
{
result += std::to_string(*i);
}
std::cout << result << std::endl;
}
Combining sounds like a job for std::accumulate.
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
auto main() -> int
{
const std::vector<int> vec{ 1, 2, 3 };
const std::string result = std::accumulate(vec.begin(), vec.end(), std::string(),
[](const std::string& s, const int value)
{
return s + std::to_string(value);
});
std::cout << result << std::endl;
}
There's an error in your code:
You call itoa() with a non-initialized char pointer. That's bad, because itoa() needs a valid buffer! Besides, itoa() is not part of the c++ standard.
Better do leave char* behind and do it with more modern C++ features, especially std::stringstream, which is a string builder, which is powerful in conversion (and also often faster than the string += operator). It builds a string by pushing elements to it with the << operator (these can be string literals, strings, numbers of all kinds), it can be extended via external operators for own data types, and it also has a lot of formatting options (e.g. number of digits, hex etc), and returns its built string with the method str().
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::vector<int> vec;
for (int i = 0;i<100;i++)
vec.push_back(i);
std::stringstream ss;
for (auto& number : vec)
ss << number;
std::cout << ss.str() << std::endl;
}
I realize that this question may have been asked several times in the past, but I am going to continue regardless.
I have a program that is going to get a string of numbers from keyboard input. The numbers will always be in the form "66 33 9" Essentially, every number is separated with a space, and the user input will always contain a different amount of numbers.
I'm aware that using 'sscanf' would work if the amount of numbers in every user-entered string was constant, but this is not the case for me. Also, because I'm new to C++, I'd prefer dealing with 'string' variables rather than arrays of chars.
I assume you want to read an entire line, and parse that as input. So, first grab the line:
std::string input;
std::getline(std::cin, input);
Now put that in a stringstream:
std::stringstream stream(input);
and parse
while(1) {
int n;
stream >> n;
if(!stream)
break;
std::cout << "Found integer: " << n << "\n";
}
Remember to include
#include <string>
#include <sstream>
The C++ String Toolkit Library (Strtk) has the following solution to your problem:
#include <iostream>
#include <string>
#include <deque>
#include <algorithm>
#include <iterator>
#include "strtk.hpp"
int main()
{
std::string s = "1 23 456 7890";
std::deque<int> int_list;
strtk::parse(s," ",int_list);
std::copy(int_list.begin(),
int_list.end(),
std::ostream_iterator<int>(std::cout,"\t"));
return 0;
}
More examples can be found Here
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
#include <iostream>
int main() {
std::string input;
while ( std::getline( std::cin, input ) )
{
std::vector<int> inputs;
std::istringstream in( input );
std::copy( std::istream_iterator<int>( in ), std::istream_iterator<int>(),
std::back_inserter( inputs ) );
// Log process:
std::cout << "Read " << inputs.size() << " integers from string '"
<< input << "'" << std::endl;
std::cout << "\tvalues: ";
std::copy( inputs.begin(), inputs.end(),
std::ostream_iterator<int>( std::cout, " " ) );
std::cout << std::endl;
}
}
#include <string>
#include <vector>
#include <sstream>
#include <iostream>
using namespace std;
int ReadNumbers( const string & s, vector <int> & v ) {
istringstream is( s );
int n;
while( is >> n ) {
v.push_back( n );
}
return v.size();
}
int main() {
string s;
vector <int> v;
getline( cin, s );
ReadNumbers( s, v );
for ( int i = 0; i < v.size(); i++ ) {
cout << "number is " << v[i] << endl;
}
}
// get string
std::string input_str;
std::getline( std::cin, input_str );
// convert to a stream
std::stringstream in( input_str );
// convert to vector of ints
std::vector<int> ints;
copy( std::istream_iterator<int, char>(in), std::istream_iterator<int, char>(), back_inserter( ints ) );
Here is how to split your string into strings along the spaces. Then you can process them one-by-one.
Generic solution for unsigned values (dealing with prefix '-' takes an extra bool):
template<typename InIter, typename OutIter>
void ConvertNumbers(InIter begin, InIter end, OutIter out)
{
typename OutIter::value_type accum = 0;
for(; begin != end; ++begin)
{
typename InIter::value_type c = *begin;
if (c==' ') {
*out++ = accum; accum = 0; break;
} else if (c>='0' && c <='9') {
accum *= 10; accum += c-'0';
}
}
*out++ = accum;
// Dealing with the last number is slightly complicated because it
// could be considered wrong for "1 2 " (produces 1 2 0) but that's similar
// to "1 2" which produces 1 0 2. For either case, determine if that worries
// you. If so: Add an extra bool for state, which is set by the first digit,
// reset by space, and tested before doing *out++=accum.
}
Try strtoken to separate the string first, then you will deal with each string.
This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Don't print space after last number
Printing lists with commas C++
#include <vector>
#include <iostream>
#include <sstream>
#include <boost/foreach.hpp>
using namespace std;
int main()
{
vector<int> VecInts;
VecInts.push_back(1);
VecInts.push_back(2);
VecInts.push_back(3);
VecInts.push_back(4);
VecInts.push_back(5);
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
ss << i << ",";
}
cout << ss.str();
return 0;
}
This prints out: 1,2,3,4,5,
However I want: 1,2,3,4,5
How can I achieve that in an elegant way?
I see there is some confusion about what I mean with "elegant": E.g. no slowing down "if-clause" in my loop. Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone through the loop.
How about this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
std::ostringstream ss;
if(!v.empty()) {
std::copy(v.begin(), std::prev(v.end()), std::ostream_iterator<int>(ss, ", "));
ss << v.back();
}
std::cout << ss.str() << "\n";
}
No need to add extra variables and doesn't even depend on boost! Actually, in addition to the "no additional variable in the loop" requirement, one could say that there is not even a loop :)
Detecting the one before last is always tricky, detecting the first is very easy.
bool first = true;
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
if (!first) { ss << ","; }
first = false;
ss << i;
}
Using Karma from Boost Spirit - has a reputation for being fast.
#include <iostream>
#include <vector>
#include <boost/spirit/include/karma.hpp>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
using namespace boost::spirit::karma;
std::cout << format(int_ % ',', v) << std::endl;
}
Try:
if (ss.tellp ())
{
ss << ",";
}
ss << i;
Alternatively, if the "if" is making you worried:
char *comma = "";
BOOST_FOREACH(int i, VecInts)
{
ss << comma << i;
comma = ",";
}
Personally, I like a solution that does not cause potential memory allocations (because the string grows larger than needed). An extra-if within the loop body should be tractable thanks to branch target buffering, but I would do so:
#include <vector>
#include <iostream>
int main () {
using std::cout;
typedef std::vector<int>::iterator iterator;
std::vector<int> ints;
ints.push_back(5);
ints.push_back(1);
ints.push_back(4);
ints.push_back(2);
ints.push_back(3);
if (!ints.empty()) {
iterator it = ints.begin();
const iterator end = ints.end();
cout << *it;
for (++it; it!=end; ++it) {
cout << ", " << *it;
}
cout << std::endl;
}
}
Alternatively, BYORA (bring your own re-usable algorithm):
// Follow the signature of std::getline. Allows us to stay completely
// type agnostic.
template <typename Stream, typename Iter, typename Infix>
inline Stream& infix (Stream &os, Iter from, Iter to, Infix infix_) {
if (from == to) return os;
os << *from;
for (++from; from!=to; ++from) {
os << infix_ << *from;
}
return os;
}
template <typename Stream, typename Iter>
inline Stream& comma_seperated (Stream &os, Iter from, Iter to) {
return infix (os, from, to, ", ");
}
so that
...
comma_seperated(cout, ints.begin(), ints.end()) << std::endl;
infix(cout, ints.begin(), ints.end(), "-") << std::endl;
infix(cout, ints.begin(), ints.end(), "> <") << std::endl;
...
output:
5, 1, 4, 2, 3
5-1-4-2-3
5> <1> <4> <2> <3
The neat thing is it works for every output stream, any container that has forward iterators, with any infix, and with any infix type (interesting e.g. when you use wide strings).
I like moving the test outside the loop.
It only needs to be done once. So do it first.
Like this:
if (!VecInts.empty())
{
ss << VecInts[0]
for(any loop = ++(VecInts.begin()); loop != VecInts.end(); ++loop)
{
ss << "," << *loop;
}
}
You can either trim the string at the end, or using single for loop instead of foreach and dont concatenate at the last iteration
Well, if you format into a stringstream anyway, you can just trim the resulting string by one character:
cout << ss.str().substr(0, ss.str().size() - 1);
If the string is empty, than the second argument says -1, which means everything and does not crash and if the string is non-empty, it always ends with a comma.
But if you write to an output stream directly, I never found anything better than the first flag.
That is unless you want to use join from boost.string algo.
This would work
stringstream ss;
BOOST_FOREACH(int const& i, VecInts)
{
if(&i != &VecInts[0])
ss << ", ";
ss << i;
}
I suspect with "elegant" you mean "without introducing a new variable". But I think I would just do it "non-elegant" if I couldn't find anything else. It's still clear
stringstream ss;
bool comma = false;
BOOST_FOREACH(int i, VecInts)
{
if(comma)
ss << ", ";
ss << i;
comma = true;
}
Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone thorough the loop.
You are saying that as if printing ss << i is one machine instruction. Come on, executing that expression will execute lots of if's and loops inside. Your if will be nothing compared to that.
cout << ss.str()<<"\b" <<" ";
You can add the "\b" backspace
This will overwrite the extra "," .
for Example :
int main()
{
cout<<"Hi";
cout<<'\b'; //Cursor moves 1 position backwards
cout<<" "; //Overwrites letter 'i' with space
}
So the output would be
H