I have a large vector.
The ways that I use multiply the run-time of the program hugely. The first is write all values to a string as they are calculated using stringstreams and later write the string to a file. The other method is to make a long string after the fact and write that to the file. However, both of these are very slow.
Is there a way to just write the vector's values to the text file immediately with line breaks?
Using std::ofstream, std::ostream_iterator and std::copy() is the usual way to do this. Here is an example with std::strings using C++98 syntax (the question was asked pre-C++11):
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> example;
example.push_back("this");
example.push_back("is");
example.push_back("a");
example.push_back("test");
std::ofstream output_file("./example.txt");
std::ostream_iterator<std::string> output_iterator(output_file, "\n");
std::copy(example.begin(), example.end(), output_iterator);
}
[Some years later]
A more modern implementation may look like:
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> example { "This", "is", "a", "test" };
std::ofstream output_file("./example.txt");
std::ostream_iterator<std::string> output_iterator(output_file, "\n");
std::copy(std::begin(example), std::end(example), output_iterator);
}
Assuming you have C++11:
#include <fstream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> v{ "one", "two", "three" };
std::ofstream outFile("my_file.txt");
// the important part
for (const auto &e : v) outFile << e << "\n";
}
Maybe I have missed something, but what is wrong with:
std::ofstream f("somefile.txt");
for(vector<X>::const_iterator i = v.begin(); i != v.end(); ++i) {
f << *i << '\n';
}
That avoids having to do potentially quadratic string concatenation, which I assume is what's killing your run-time.
You can use std::copy and std::ostream_iterator.
Related
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using std::ifstream;
using std::string;
int main()
{
ifstream NameList("LineUp.txt");
string List = "LineUp.txt";
while (getline(NameList, List))
{
std::vector<string> names = {List};
std::sort(names.begin(), names.end());
}
NameList.close();
return 0;
}
I know that I am supposed to put "[] (string a, string b)" at the end of the sort command but I am unable to. My IDE keeps telling me to remove the "string" identifier, or any identifier I have, and then it throws a fit because it can't identify a or b. I just want to sort this shit by alphabet.
std::vector<string> names = {List};
This vector only lives in the scope of the while loop. That means, you are creating a new vector for each single line that is read.
You then sort this vector, which is quite useless, since
a) it contains only one line and
b) you do nothing else with it and it gets destroyed at the closing }
Solution:
move the vector to before the while loop
move the sort() call to after the while loop
inside the loop, call names.push_back() in order to add the current line to the list
Things will go much smoother if your variables have the correct names as well. List should not be named like that, because it's used in getline(), so it's just one line of the list. NameList should be named file, because that's what you access. The list with the names is the vector.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using std::ifstream;
using std::string;
int main()
{
ifstream file("LineUp.txt");
std::vector<string> names;
string line;
while (getline(file, line))
{
names.push_back(line);
}
std::sort(names.begin(), names.end());
file.close();
for (auto& name : names)
{
std::cout << name << '\n';
}
return 0;
}
An assignment wants me to make a function that makes all lowercase characters uppercase.
Here's my code:
main.cpp:
#include <iostream>
#include "Function.h"//Includes function file in main file
using namespace std;
int main(){
char a;
cout<<"Enter some words:";
cin.get(a);//Collects info from user
strcap(a);
cout<<a;
}
function.cpp:
#include <iostream>
#include "Function.h"
using namespace std;
char strcap(char a){
while (a!='\n'){
if (a>='a' && a<='z'){
a-=32;//
}
cin.get(a); //get the next letter
}
}
function.h:
#include <iostream>
char strcap(char a);
While the approach you have taken approximates a standard C approach, you have not provided adequate storage to read more than a single character. You could wrap your cin.get(a); strcap(a); cout << a; in a while loop, that would be an approach that is about a decade out of place in C++. Using std::basic::string provides automatic memory management for your input and std::transform makes it simple to apply a transformation to all elements of a container.
The example for std::transform provides exactly what you need, but it doesn't explain how to split the operation up into a separate header and source file. If after reading the documentation you are still stuck, the you can do something similar to the following.
Your header for function.h as you have it simply needs to provide for the declaration of strcap, e.g.
#include <string>
void strcap (std::string& s);
Your implementation for function.cpp likewise just needs to provide for the definition of strcap:
#include <cctype>
#include <algorithm>
#include "function.h"
void strcap (std::string& s)
{
std::transform (s.begin(), s.end(), s.begin(),
[](unsigned char c) -> unsigned char { return std::toupper(c); });
}
(note: the trailing-return-type "-> unsigned char" can be omitted above and it will be deduced properly)
Your main.cpp would then be:
#include <iostream>
#include "function.h"
int main (void) {
std::string s;
std::cout << "enter string: ";
if (getline (std::cin, s)) {
strcap(s);
std::cout << s << '\n';
}
}
Example Use/Output
Compile as you normally would, but you will require the language standard of at least -std=c++11, and then, e.g.
$ ./main
enter string: My dog has fleas
MY DOG HAS FLEAS
Also note, if you do not want to use std::transform, you can use a range-based-for loop to iterate over each character in your string converting to uppercase as well. Your strcap() function would then be:
void strcap (std::string& s)
{
for (auto& c : s)
c = toupper(c);
}
And if for some reason your compiler doesn't support the range-based for loop, then you can also use basic std::string:iterator to iterate over the string providing the conversion, e.g.
void strcap (std::string& s)
{
for (std::string::iterator it = s.begin(); it != s.end(); it++)
*it = toupper(*it);
}
There are several different approaches you can take.
Look things over and let me know if you have any further questions.
Code::Blocks Compiler Options
Just to make sure we are on the same sheet of paper, you should see:
So I recently discovered the use of map and vectors, however, I'm having trouble of trying to figure a way to loop through a vector containing strings.
Here's what I've tried:
#include <string>
#include <vector>
#include <stdio>
using namespace std;
void main() {
vector<string> data={"Hello World!","Goodbye World!"};
for (vector<string>::iterator t=data.begin(); t!=data.end(); ++t) {
cout<<*t<<endl;
}
}
and when I try to compile it, I get this error:
cd C:\Users\Jason\Desktop\EXB\Win32
wmake -f C:\Users\Jason\Desktop\EXB\Win32\exbint.mk -h -e
wpp386 ..\Source\exbint.cpp -i="C:\WATCOM/h;C:\WATCOM/h/nt" -w4 -e25 -zq -od -d2 -6r -bt=nt -fo=.obj -mf -xs -xr
..\Source\exbint.cpp(59): Error! E157: col(21) left expression must be integral
..\Source\exbint.cpp(59): Note! N717: col(21) left operand type is 'std::ostream watcall (lvalue)'
..\Source\exbint.cpp(59): Note! N718: col(21) right operand type is 'std::basic_string<char,std::char_traits<char>,std::allocator<char>> (lvalue)'
Error(E42): Last command making (C:\Users\Jason\Desktop\EXB\Win32\exbint.obj) returned a bad status
Error(E02): Make execution terminated
Execution complete
I tried the same method using map and it worked. The only difference was I changed the cout line to:
cout<<t->first<<" => "<<t->last<<endl;
Add iostream header file and change stdio to cstdio.
#include <iostream>
#include <string>
#include <vector>
#include <cstdio>
using namespace std;
int main()
{
vector<string> data={"Hello World!","Goodbye World!"};
for (vector<string>::iterator t=data.begin(); t!=data.end(); ++t)
{
cout<<*t<<endl;
}
return 0;
}
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> data = {"Hello World!", "Goodbye World!"};
for (std::vector<std::string>::iterator t = data.begin(); t != data.end(); t++) {
std::cout << *t << std::endl;
}
return 0;
}
Or with C++11 (or higher):
#include <iostream>
#include <vector>
#include <string>
typedef std::vector<std::string> STRVEC;
int main()
{
STRVEC data = {"Hello World!", "Goodbye World!"};
for (auto &s: data) {
std::cout << s << std::endl;
}
return 0;
}
From the Open Watcom V2 Fork-Wiki on the C++ Library Status page:
<string>
Mostly complete. Although there are no I/O operators, all other member functions and string operations are available.
A workaround (besides implementing the << operator) would be asking the string instances for the C string:
for (vector<string>::iterator t = data.begin(); t != data.end(); ++t) {
cout << t->c_str() << endl;
}
This of course only works as long as the strings don't contain zero byte values.
When I compile your code, I get:
40234801.cpp:3:17: fatal error: stdio: No such file or directory
#include <stdio>
^
You clearly have a header called "stdio" in your include path that you haven't shown us.
If you change that line to the standard #include <iostream>, then the only reported error is that you wrote void main() instead of int main(). Fix that, and it will build and run.
In passing, note also that using namespace should be avoided.
I found a solution to my own issue. Instead of using a c_str, I used std::string and switched to using the G++ compiler instead of Open Watcom
Instead of having:
char *someString="Blah blah blah";
I instead replaced it with:
string someString="Blah blah blah";
This way is much more efficient and easier.
I'm trying to understand the answer provided here, but I can't seem to make it work.
Here is what I've tried:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <fstream>
int main()
{
std::string path("numbersfile");
std::vector<int> myVector{1,16,32,64};
std::vector<int> newVector{};
std::ofstream FILE(path,std::ios::out | std::ofstream::binary);
std::copy(myVector.begin(),myVector.end(),std::ostreambuf_iterator<char>(FILE));
std::ifstream INFILE(path,std::ios::in | std::ifstream::binary);
std::istreambuf_iterator<char> iter(INFILE);
//std::copy(iter.begin(),iter.end(),std::back_inserter(newVector)); //this doesn't compile
std::copy(iter,std::istreambuf_iterator<char>{},std::back_inserter(newVector)); // this leaves newVector empty
}
newVector is still empty after the last copy. How could the last statement be updated to populate newVector?
The file is not ready to be read by the time the second copy is called. (Thanks to Piotr Skotnicki for his answer in the comments)
A call to flush allows the program to work:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <fstream>
int main()
{
std::string path("numbersfile");
std::vector<int> myVector{1,16,32,64};
std::vector<int> newVector{};
std::ofstream FILE(path,std::ios::out | std::ofstream::binary);
std::copy(myVector.begin(),myVector.end(),std::ostreambuf_iterator<char>(FILE));
FILE.flush(); // required here
std::ifstream INFILE(path,std::ios::in | std::ifstream::binary);
std::istreambuf_iterator<char> iter(INFILE);
//std::copy(iter.begin(),iter.end(),std::back_inserter(newVector)); //this doesn't compile
std::copy(iter,std::istreambuf_iterator<char>{},std::back_inserter(newVector)); // this leaves newVector empty
return 0;
}
The ofstream is still in scope when the ifstream is created. Had the ofstream's destructor been called then the file would also have been ready for the ifstream. In the following program the ifstream is automatically destructed:
#include <algorithm>
#include <fstream>
#include <iterator>
#include <vector>
std::string filename("numbersfile");
std::vector<double> myVector{1.342, 16.33, 32.1, 12364};
void write_vector_to_file(const std::vector<double>& myVector, std::string filename);
std::vector<double> read_vector_from_file(std::string filename);
int main()
{
write_vector_to_file(myVector, filename);
auto newVector{read_vector_from_file(filename)};
return 0;
}
void write_vector_to_file(const std::vector<double>& myVector, std::string filename)
{
std::ofstream ofs(filename, std::ios::out | std::ofstream::binary);
std::ostream_iterator<double> osi{ofs," "};
std::copy(myVector.begin(), myVector.end(), osi);
}
std::vector<double> read_vector_from_file(std::string filename)
{
std::vector<double> newVector{};
std::ifstream ifs(filename, std::ios::in | std::ifstream::binary);
std::istream_iterator<double> iter{ifs};
std::istream_iterator<double> end{};
std::copy(iter, end, std::back_inserter(newVector));
return newVector;
}
There are a number of flaws in your code:
you define a variable named FILE THIS IS BAD BAD BAD. FILE is a name of an already existing object, it's comparable to naming an instance of a vector as: std::vector<int>array{}.
Not only is it confusing it's extremely dangerous as it will almost certainty lead to naming clashes. Plus, all capitol names should be reserved for macros.
you never check if the file is actually opened, if it isn't the compiler will not warn you and the stream will not give any indication of failure (unless explicitly checked). So, you should always check. The simplest way is too use the streams boolean operator:
if (!ifile) throw std::runtime_error("error opening file");
you wrote that this doesn't compile:
std::copy(iter.begin(),iter.end(),std::back_inserter(newVector));
Why would this work? Iterators themselves don't have begin and end functions, the objects associated with the iterator have those methods.
Piecing all that together here is a modified version of your code:
{
std::string path("numbersfile");
std::vector<int> myVector{ 1,16,32,64 };
std::vector<int> newVector{};
std::ofstream outfile(path, std::ios_base::binary);
std::copy(myVector.begin(), myVector.end(), std::ostreambuf_iterator<char>(outfile));
outfile.close();
std::ifstream infile(path,std::ios_base::binary);
std::istreambuf_iterator<char> iter(infile);
std::copy(iter, std::istreambuf_iterator<char>(), std::back_inserter(newVector)); // this leaves newVector empty
infile.close(); // close explicilty for consistency
}
I am trying to use the stream iterators to read and output words from the console. Here is my attempt:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
vector<string> stringVec;
copy(istream_iterator<string>(cin), istream_iterator<string>(), back_inserter(stringVec));
sort(stringVec.begin(), stringVec.end());
unique_copy(stringVec.cbegin(), stringVec.cend(), ostream_iterator<string> (cout, "\n"));
return 0;
}
When I input "this is it" and press Return in the console, the cursor there keeps on blinking (indicating that it's waiting for input).
Can anyone please offer some insights on my approach?
Thanks in advance.
You need to provide a EOF for istream_iterator<string>(), which constructs the end-of-stream iterator.
Use Ctrl+Z or F6 or (Ctrl+D on linux ) to stop getting input from stream
In your case, you can use getline and istringstream. It reads a string until \n and then passes it to copy.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <sstream>
...
vector<string> stringVec;
string str;
getline(cin, str);
istringstream ss(str);
copy(istream_iterator<string>(ss),
istream_iterator<string>(),
back_inserter(stringVec));
sort(stringVec.begin(), stringVec.end());
unique_copy(stringVec.cbegin(),
stringVec.cend(),
ostream_iterator<string> (cout, "\n"));
Two same questions in a day, you can read this.