How Do I Print a Vector of Tuples? - c++

So I'm trying to make a vector that contains tuples containing two ints, and I'm acquiring the ints from a text file source. To make sure I have the vector I want, I'm trying the print out my contents, but the output is not showing me anything. I'm not sure if it's because of my code, and where I put my text file. I'm just stuck at this point. If anything could help me with this, I'd appreciate it very much. Thanks
using namespace std;
int main()
{
ifstream file("source.txt");
typedef vector<tuple<int, int>> streets;
streets t;
int a, b;
if (file.is_open())
{
while (((file >> a).ignore() >> b).ignore())
{
t.push_back(tuple<int, int>(a, b));
for (streets::const_iterator i = t.begin();i != t.end();++i)
{
cout << get<0>(*i) << endl;
cout << get<1>(*i) << endl;
}
cout << get<0>(t[0]) << endl;
cout << get<1>(t[1]) << endl;
}
}
file.close();
system("pause");
return 0;
Here's my text file and where I placed it
enter image description here
Here's my output from debugging, if that's important

You should use a loop, that will print one tuple at a time.
Complete minimal example:
#include <iostream>
#include <tuple>
#include <vector>
#include <fstream>
using namespace std;
int main(void) {
std::ifstream infile("source.txt");
vector<tuple<int, int>> streets;
int a, b;
while (infile >> a >> b)
{
streets.push_back(tuple<int, int>(a, b));
}
infile.close();
for(auto& tuple: streets) {
cout << get<0>(tuple) << " " << get<1>(tuple) << endl;
}
return 0;
}
Output:
1 2
3 4
5 6
7 8

Related

Having trouble with std::string::compare() return values in c++

Relatively new to c++.
Having trouble understanding an issue I am having with the compare() function returning 1 instead of 0.
I have a program which reads a text file containing an arbitrary number of questions and answers for a quiz. It is formatted as such:
Q: How many days in a week?
A: seven
I have three files, main.cpp, Quiz.cpp, and Quiz.h:
main.cpp:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include "Quiz.h"
using namespace std;
int main(int argc, char* argv[]){
srand(unsigned(time(0)));
vector<Quiz> quizVector;
ifstream inputQuiz;
inputQuiz.open(argv[1]);
string q, a;
int questionCount = 0;
if(inputQuiz.is_open()){
getline(inputQuiz, q);
getline(inputQuiz, a);
while(!inputQuiz.eof()){
Quiz *instance = new Quiz(q, a);
quizVector.push_back(*instance);
questionCount++;
getline(inputQuiz, q);
getline(inputQuiz, a);
}
}
random_shuffle(quizVector.begin(), quizVector.end());
string userInput;
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
return 0;
}
Quiz.cpp:
#include <string>
#include "Quiz.h"
int Quiz::score = 0;
std::string Quiz::getQuestion(){
return question;
}
std::string Quiz::getAnswer(){
return answer;
}
Quiz.h:
#ifndef QUIZ_H
#define QUIZ_H
class Quiz{
private:
std::string question {""};
std::string answer {""};
public:
Quiz() = default;
Quiz(std::string q, std::string a) : question {q}, answer {a} {}
std::string getQuestion();
std::string getAnswer();
};
#endif
My problem lies within main.cpp:
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
When I input the correct answer corresponding to each question, compare() does not return 0, but consistently returns 1. There are no leading or trailing spaces at the start or ends of each line in the text file. Am I misunderstanding how getline() or compare() works? Is it something else? Any help is appreciated!
I see a number of problems with this code:
std::random_shuffle() is deprecated in C++14 and removed in C++17, use std::shuffle() instead.
you are not validating that argv contains an input parameter before using it.
Your use of eof() in the while loop is wrong. For instance, if the last question/answer pair in the file is terminated by EOF instead of a line break, getline() will still return the question/answer to you, but it will also set the eofbit flag on the stream, which will cause eof() to return true and thus you will skip saving the last pair into the vector. The stream is not technically in a failed state yet in this situation (see the diagram at https://en.cppreference.com/w/cpp/io/basic_ios/eof), so you shouldn't skip the last pair if it terminates with EOF rather than a line break.
Your while loop is leaking memory.
you don't need questionCount at all, use quizVector.size() instead. Or better, a range-for loop.
you don't really need to use compare() at all, you can use operator== instead. But, if you do use compare(), you should take into account that it is case-sensitive (as is operator==). You should also take advantage of the fact that compare() lets you specify an index to start comparing from, so you can ignore the A: prefix in the stored answer (alternatively, you could just strip off the Q: and A: prefixes when storing the question/answer in Quiz's constructor). Otherwise, you can use your compiler's strcmpi() function instead (if it offers one).
Try something more like this instead:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <random>
#include <cctype>
#include "Quiz.h"
using namespace std;
string toLowercase(string s) {
transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return tolower(c); }
);
return s;
}
int main(int argc, char* argv[]){
if (argc < 2){
cerr << "Please specify a file to open!" << endl;
return 0;
}
ifstream inputQuiz(argv[1]);
if (!inputQuiz.is_open()) {
cerr << "Can't open the file!" << endl;
return 0;
}
vector<Quiz> quizVector;
string q, a, userInput;
while (getline(inputQuiz, q) && getline(inputQuiz, a)) {
quizVector.emplace_back(q, a);
}
random_device rd;
mt19937 g(rd());
shuffle(quizVector.begin(), quizVector.end(), g);
for(auto &quiz : quizVector){
cout << quiz.getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
userInput = toLowercase(userInput);
a = toLowercase(quiz.getAnswer());
if (a == ("a: " + userInput)) {
// or:
// if (a.compare(2, string::npos, userInput) == 0) {
// or, if you strip off "A:" beforehand:
// if (a == userInput) {
cout << "Correct." << endl;
}
else {
cout << "Incorrect." << endl;
}
}
return 0;
}

Vector of strings works correctly before sorting, but afterwards it can't do anything

I was working on a problem which required me to sort vector of strings at certain point. It caused me a lot of problems so I decided to extract the problematic part and I can't figure out what seems to be the problem.
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
bool myComp(string a, string b){
return a<b;
}
int main(){
vector<string> students(50000);
int i = 0;
while(true){
string input;
getline(cin, students[i]);
if(!students[i].empty()){
i++;
}
else{
break;
}
}
cout << students[2] << endl << students[1] << endl;
sort(students.begin(), students.end());
cout << students[2] << endl << students[1];
return 0;
}
At first I thought that input was wrong (problem specifically requests to read until empty line), but it turned out that program works correctly up to moment of sorting. I would be very grateful if anyone was to clear this out for me I am banging my head for more than an hour.
The obvious issue with your code is that you have a vector of 50000 strings. You then try an sort that vector of 50000 strings. It seems obvious that you really want the size of the vector to equal the number of strings input. The easy way to do that is to grow the vector as you input strings. Use the push_back method for that.
Here's some code
vector<string> students; // initial size of vector is zero
int i = 0;
while(true){
string input;
getline(cin, input); // read into the input variable
if (input.empty()) // break if input is empty
break;
students.push_back(input); // add the input to the vector
}
Now with the vector sized correctly you should find sorting it to be no problem
cout << students[2] << endl << students[1] << endl;
sort(students.begin(), students.end());
cout << students[2] << endl << students[1];
The problem is using incorrect arguments in the call of std::sort.
sort(students.begin(), students.end());
The vector students contains 50000 elements
vector<string> students(50000);
It seems you mean
#include <iterator>
//...
sort(students.begin(), std::next( students.begin(), i ));
or
sort(students.begin(), std::next( students.begin(), i ), myComp );
where myComp should be defined at least like
bool myComp( const string &a, const string &b){
return a<b;
}
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> students;
students.reserve(50000); // want to avoid `students` reallocation for first
// 50'000 entries but size is still zero (`0`)
std::string line;
// read until end-of-input or empty line
while(std::getline(std::cin, line) && !line.empty())
students.push_back(line); // no reallocation for first 50'000 entries!
if(students.size() < 3)
{
std::cerr << "Need at least three students for example\n";
return EXIT_FAILURE;
}
std::cout << students[2] << '\n' << students[1] << '\n';
std::partial_sort( // Only pick out three "smallest" strings for example
students.begin(), // no need to sort more than necessary with 50'000 :-)
std::next(students.begin(), 3),
students.end());
std::cout << students[2] << '\n' << students[1] << std::endl;
return EXIT_SUCCESS;
}
You have written a comparator function myComp() but you haven't used it. I'd suggest using it as the third parameter for sort() and see if things get better. i.e.;
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
using namespace std;
bool myComp(string a, string b){
return a<b;
}
int main(){
vector<string> students(50000);
int i = 0;
while(true){
string input;
getline(cin, students[i]);
if(!students[i].empty()){
i++;
}
else{
break;
}
}
cout << students[2] << endl << students[1] << endl;
sort(students.begin(), students.end(), myComp);
cout << students[2] << endl << students[1];
return 0;
}

Inputting values into an array from a file with C++

The file does open and I get the message "File opened successfully". However I can't input data from the array in file "random.csv" into my inputFile object.
The data in random.csv is:
Boston,94,-15,65
Chicago,92,-21,72
Atlanta,101,10,80
Austin,107,19,81
Phoenix,112,23,88
Washington,88,-10,68
Here is my code:
#include "main.h"
int main() {
string item; //To hold file input
int i = 0;
char array[6];
ifstream inputFile;
inputFile.open ("random.csv",ios::in);
//Check for error
if (inputFile.fail()) {
cout << "There was an error opening your file" << endl;
exit(1);
} else {
cout << "File opened successfully!" << endl;
}
while (i < 6) {
inputFile >> array[i];
i++;
}
for (int y = 0; y < 6; y++) {
cout << array[y] << endl;
}
inputFile.close();
return 0;
}
Hello and welcome to Stack Overflow (SO). You can use std::getline() to read each line from the file, and then use boost::split() to split each line into words. Once you have an array of strings for each line, you can use a container of your liking to store the data.
In the example below I've used an std::map that stores strings and a vector of ints. Using a map will also sort the entrances using the key values, which means that the final container would be in alphabetical order. The implementation is very basic.
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include <ctype.h>
typedef std::map<std::string,std::vector<int>> ContainerType;
void extract(ContainerType &map_, const std::string &line_)
{
std::vector<std::string> data;
boost::split(data, line_, boost::is_any_of(","));
// This is not the best way - but it works for this demo.
map_[data[0]] = {std::stoi(data[1]),std::stoi(data[2]),std::stoi(data[3])};
}
int main()
{
ContainerType map;
std::ifstream inputFile;
inputFile.open("random.csv");
if(inputFile.is_open())
{
std::string line;
while( std::getline(inputFile,line))
{
if (line.empty())
continue;
else
extract(map,line);
}
inputFile.close();
}
for (auto &&i : map)
{
std::cout<< i.first << " : ";
for (auto &&j : i.second)
std::cout<< j << " ";
std::cout<<std::endl;
}
}
Hope this helps.

2D Dynamic Array Based on User Input [duplicate]

This question already has answers here:
Finding size of dynamically allocated array
(8 answers)
Closed 4 years ago.
Scenario:
Read numbers from file and create dynamic 2d array accordingly
The first line of data file represents the rooms and rest of the lines represent the number of person in the room
For example:
4
4
6
5
3
total 4 rooms, 1st room has 4 people, 2nd room has 6 people...
So far this is my code, how do I check I've created the dynamic array with correct size?
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
ifstream readFirstLine("data.txt");
ifstream readData("data.txt");
string line;
int numRoom, numPerson = 0;
int i = -1;
while (getline(readFirstLine, line))
{
istringstream linestream(line);
if (i == -1)
{
linestream >> numRoom;
cout << "numRoom:" << numRoom << endl;
break;
}
}
readFirstLine.close();
int** numRoomPtr = new int*[numRoom];
while (getline(readData, line))
{
istringstream linestream(line);
if (i == -1)
{
}
else
{
linestream >> numPerson;
numRoomPtr[i] = new int[numPerson];
cout << "i:" << i << endl;
cout << "numPerson:" << numPerson<< endl;
}
i++;
}
readData.close();
return 0;
}
A better way to do your current program, using std::vector, could be like this:
#include <iostream>
#include <vector>
#include <fstream>
int main()
{
std::ifstream dataFile("data.txt");
// Get the number of "rooms"
unsigned roomCount;
if (!(dataFile >> roomCount))
{
// TODO: Handle error
}
// Create the vector to contain the rooms
std::vector<std::vector<int>> rooms(roomCount);
for (unsigned currentRoom = 0; currentRoom < roomCount; ++currentRoom)
{
unsigned personCount;
if (dataFile >> personCount)
{
rooms[currentRoom].resize(personCount);
}
else
{
// TODO: Handle error
}
}
// Don't need the file anymore
dataFile.close();
// Print the data
std::cout << "Number of rooms: " << rooms.size() << '\n';
for (unsigned currentRoom = 0; currentRoom < rooms.size(); ++currentRoom)
{
std::cout << "Room #" << currentRoom + 1 << ": " << rooms[currentRoom].size() << " persons\n";
}
}
As you can see, it's now possible to get the "sizes" of the data after you're done with the reading from the file.

Using the find() function with sets

I have just encountered this chapter in my book and I dont really understand how find() works. I tried to create a simple function to check how the find() function works, but I am getting a multitude of errors in my code.
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> setA(1,2);
int item;
cout << "Enter a number: ";
cin >> item;
int setIter;
setIter = setA.find(item);
if (setIter != setA.end())
{
cout << "It's in the list." << endl;
}
return 0;
}
Here is the correct implementation of your program...
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> setA;
setA.insert(1); // use insert function
setA.insert(2);
set<int>::iterator setIter; // take set iterator
int item;
cout << "Enter a number: ";
cin >> item;
setIter = setA.find(item);
if (setIter != setA.end())
{
cout << "It's in the list." << endl;
}
return 0;
}
You are making two mistakes in your program. First you are initializing set using constructor which does not work so you have to use insert function of set. Secondly you are taking iterator as an int which is not correct. Iterator is basically a pointer of set type. So you have to take the iterator of set
Your code has two issues- first is the usage of constructor and the other is assigning set iterator returned by set.find() to an int. Here is the corrected code:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> setA({1,2});
int item;
cout << "Enter a number: ";
cin >> item;
set<int>::iterator setIter = setA.find(item);
if (setIter != setA.end())
{
cout << "It's in the list." << endl;
}
return 0;
}