I'm trying to write a program that first checks if a name is in a vector and if not then adds it to the vector. My code seems to have difficulties with parsing, at least that's what I get out of it. I tried changing the string to a char but it did not help me much.
#include <iostream>
#include <vector>
#include <string>
bool isinVector(std::string uElement, std::vector<std::string> uArray)
{
for (unsigned int i = 0; i <= sizeof(uArray); i++) {
if (uArray[i] == uElement) {
return true;
}
else {
return false;
}
}
}
int main()
{
bool trigger = false;
while (!trigger) {
std::vector<std::string> names;
names.push_back("Bart");
std::string newName;
getline(std::cin, newName);
if (isinVector(newName, names))
{
std::cout << "true" << std::endl;
trigger = true;
}
else
{
std::cout << "false" << std::endl;
names.push_back(newName);
for (int i = 0; i <= sizeof(names); i++) {
std::cout << names[i] << std::endl;
}
}
}
}
I made some adjustments to your code, removing your isinVector function and using a lambda inside the main function instead. In the future please provide a concise question and example.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using std::vector;
using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::find_if;
int main(){
bool trigger = false;
while (!trigger) {
vector<string> names;
names.push_back("Bart");
string newName;
getline(cin, newName);
if(find_if(names.begin(), names.end(), [newName] (const string& name){
return !name.compare(newName);
}) != names.end()){
cout << "true" << endl;
trigger = true;
}
else{
cout << "false" << endl;
names.push_back(newName);
for (size_t i = 0; i < names.size(); i++) {
cout << names.at(i) << endl;
}
}
}
return 0;
}
The code uses std::find_if to check if the element exists in the vector. If std::find_f does not return the iterator to uArray.end() Then the element exists. Also your for loop used sizeof which is incorrect, use the vector.size method. And you were looping until <= , it should be < uArray.size() And it's safer to access elements in the vector through the .at method rather than an index [] since the .at will throw an out_of_range exception.
Among the things wrong in the updated post.
Improper use of sizeof
Reinventing a standard algorithm
Lack of error checking
Consider the tasks you're trying to accomplish. You want to:
Initialize a starting vector containing the name Bart
Continuously read new names. For each new name read:
a. Check to see if it is already in the vector.
if it is present terminate the read loop
else add it to the vector, and print the entire vector
This sequence of operations can be accomplished with stepwise refinement.
Step 1. Read names
First, you need to be able to continuously read names:
#include <iostream>
#include <string>
int main()
{
std::string name;
while (std::getline(std::cin, name))
std::cout << name << '\n';
}
Simple enough. Running this will echo any strings you type, one at a time, separated by newlines.
Step 2. Accumulate names in a vector
Next, we need to add a vector to hold the strings we're reading, with an initial population of the name "Bart". For this pass we'll be just putting every string we read into the vector
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> names = { "Bart" };
std::string name;
while (std::getline(std::cin, name))
{
names.emplace_back(name);
for (auto const& s : names)
std::cout << s << ' ';
std::cout.put('\n');
}
}
In addition to what was done prior, we're now accumulating strings in the vector, including duplicates, and reporting the vector content after each name read. This gets us closer to our stated goal.
Step 3: Conditional loop exit based on duplicate detection
Now we need to check for duplicates, and terminate the loop once it happens. We can do this using std::find. The final code is below:
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> names = { "Bart" };
std::string name;
while (std::getline(std::cin, name))
{
if (std::find(names.begin(), names.end(), name) != names.end())
break;
names.emplace_back(name);
for (auto const& s : names)
std::cout << s << ' ';
std::cout.put('\n');
}
}
That's it. This is a simple task, but it lends itself nicely to an example of how you break a multi-part task down to manageable objectives , then build it in pieces.
Hope you found it useful.
Now my code looks like this:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
bool isinVector (std::string uElement, std::vector<std::string> uArray) {
bool invector = false;
std::vector<std::string>::iterator it = std::find(uArray.begin(),
uArray.end(),uElement);
if(it != uArray.end()){
invector = true;
}
return invector;
}
int main(){
bool trigger = false;
std::string name;
std::vector<std::string> names = { "Bart" };
while (std::getline(std::cin, name)){
if (isinVector(name, names)) {
std::cout << "true" << std::endl;
break;
}
else
{
std::cout << "false" << std::endl;
names.emplace_back(name);
}
}
return 0;
}
and it works, thanks a lot guys!
Related
I am pretty new to c++. I am trying to read a file in line by line and store the input into several arrays.
Because I don't know the size of input file, I have this to get the number of lines in the file
while (std::getline(inputFile, line)){
++numOfLines;
std::cout << line << std::endl;
}
Now I want to use the numOfLines as the size of arrays, but i cannot get it run by having this
std::string *firstName= new std::string[numOfLines];
std::string *lastName= new std::string[numOfLines];
for (int i = 0; i < numOfLines; ++i)
{
line >> firstName[i];
}
I guess it is because it has reached the end of the file after the while loop. But I do not know how to solve this problem. Is there a way to scan the input file in and store the value into array at the same time?
If you use std::vector you don't need to know ahead the lines count. You can use vector method push_back to insert new elements into it. Try use something like this:
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
std::vector<std::string> first_names;
std::string line;
ifstream input_file;
while (std::getline(input_file, line)){
first_names.push_back(line);
}
for (size_t i = 0; i < first_names.size(); i++) {
std::cout << first_names[i] << std::endl;
}
return 0;
}
I don't know if you have ever taken a course related to Data Structures & Algorithms,
in which you will learn to use Containers (such as:
vector,
deque,
list, etc.) instead of Primitive Data Structures.
Please notice that although the follow example chooses vector as its container, it could vary according to different contexts. Say you are handling gigantic mount of data, you might want to use list instead`1,2,3.
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
// alias long type
// #see: https://en.cppreference.com/w/cpp/language/type_alias
using NameVector = std::vector<std::string>;
int handleLine(std::string line, NameVector &firstNames)
{
// TODO implement your line handler here
firstNames.push_back(line);
return 0;
}
int handleFile(std::ifstream inputFile, NameVector &firstNames)
{
std::string line;
for (int lineNum = 1;
// invoke `good` to check if there is any error
inputFile.good()
&&
std::getline(inputFile, line);
lineNum++)
{
std::cout << "Current line number : (" << lineNum << ")" << std::endl;
std::cout << "Current line content: (" << line << ")" << std::endl;
handleLine(line, &firstNames);
}
return 0;
}
int main()
{
std::string path; // = R"(HERE GOES YOUR FILE PATH)";
// Using **Raw string**
std::ifstream inputFile { path }; // Initialize `inputFile`
NameVector firstNames;
handleFile(inputFile, firstNames);
for (auto firstName : firstNames)
{
std::cout << firstName << std::endl;
}
return 0;
}
I'm a beginner in c++ and required to write a c++ program to read and print a csv file like this.
DateTime,value1,value2
12/07/16 13:00,3.60,50000
14/07/16 20:00,4.55,3000
May I know how can I proceed with the programming?
I manage to get the date only via a simple multimap code.
I spent some time to make almost (read notice at the end) exact solution for you.
I assume that your program is a console application that receives the original csv-file name as a command line argument.
So see the following code and make required changes if you like:
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <string>
std::vector<std::string> getLineFromCSV(std::istream& str, std::map<int, int>& widthMap)
{
std::vector<std::string> result;
std::string line;
std::getline(str, line);
std::stringstream lineStream(line);
std::string cell;
int cellCnt = 0;
while (std::getline(lineStream, cell, ','))
{
result.push_back(cell);
int width = cell.length();
if (width > widthMap[cellCnt])
widthMap[cellCnt] = width;
cellCnt++;
}
return result;
}
int main(int argc, char * argv[])
{
std::vector<std::vector<std::string>> result; // table with data
std::map<int, int> columnWidths; // map to store maximum length (value) of a string in the column (key)
std::ifstream inpfile;
// check file name in the argv[1]
if (argc > 1)
{
inpfile.open(argv[1]);
if (!inpfile.is_open())
{
std::cout << "File " << argv[1] << " cannot be read!" << std::endl;
return 1;
}
}
else
{
std::cout << "Run progran as: " << argv[0] << " input_file.csv" << std::endl;
return 2;
}
// read from file stream line by line
while (inpfile.good())
{
result.push_back(getLineFromCSV(inpfile, columnWidths));
}
// close the file
inpfile.close();
// output the results
std::cout << "Content of the file:" << std::endl;
for (std::vector<std::vector<std::string>>::iterator i = result.begin(); i != result.end(); i++)
{
int rawLen = i->size();
for (int j = 0; j < rawLen; j++)
{
std::cout.width(columnWidths[j]);
std::cout << (*i)[j] << " | ";
}
std::cout << std::endl;
}
return 0;
}
NOTE: Your task is just to replace a vector of vectors (type std::vector<std::vector<std::string>> that are used for result) to a multimap (I hope you understand what should be a key in your solution)
Of course, there are lots of possible solutions for that task (if you open this question and look through the answers you will understand this).
First of all, I propose to consider the following example and to try make your task in the simplest way:
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
using namespace std;
int main()
{
string str = "12/07/16 13:00,3.60,50000";
stringstream ss(str);
vector<string> singleRow;
char ch;
string s = "";
while (ss >> ch)
{
s += ch;
if (ss.peek() == ',' || ss.peek() == EOF )
{
ss.ignore();
singleRow.push_back(s);
s.clear();
}
}
for (vector<string>::iterator i = singleRow.begin(); i != singleRow.end(); i++)
cout << *i << endl;
return 0;
}
I think it can be useful for you.
I'm getting a strange error when trying to iterate a Map of Vectors. I'm using the Stanford CS106B class libraries for this project and when I try to compile the code I get an error telling me that "itr has no member named 'first' "
I have tried searching for solutions to this problem and I have found many similar entries but the answers seem to mimic what I'm doing. I'm sure I'm missing something simple...
#include <iostream>
#include <fstream>
#include <string>
#include "console.h"
#include "simpio.h" // for getLine
#include "strlib.h"
#include "vector.h"
#include "queue.h"
#include "map.h"
#include <iterator>
using namespace std;
void CountLetters(ifstream &filename) {
int index=0;
Vector<int> counts;
for (int i=0; i<=26; i++) {
counts.add(0);
}
char c;
while (!filename.eof()) {
c=filename.get();
index=c-'a';
if (index>=0 && index<26) {
c=stringToChar(toLowerCase(charToString(c)));
counts[index]++;
}
}
for (int y=0; y<=26; y++) {
cout << char('a'+y) << ": " << counts[y] << endl;
}
filename.close();
}
Map <string, Vector<char> > assembleSets (ifstream &in, int seed) {
Map <string, Vector<char> > letterSets;
char c;
Vector<char> workingText;
string letterSet;
while(!in.eof()) {
if (workingText.size()<seed) { // Build the intial set of "seed" letters.
c=in.get();
workingText.add(c);
}
else {
c=in.get();
letterSet.clear();
for (int i=0; i<workingText.size()-1; i++) {
letterSet+=workingText[i]; // add the letter to the letter set.
workingText[i]=workingText[i+1]; // move the letter down one in the vector (simulate queue).
}
letterSet+=workingText[seed-1];
workingText[seed-1]=c; // add the newwest letter to the workingText but do not add it to the letter set.
// Check to see if the letter set exists already, if not, add it.
if (!letterSets.containsKey(letterSet)) {
Vector<char> blank;
letterSets.add(letterSet,blank);
letterSets[letterSet].add(c);
}
else {
// Add the next character to the vector of characters for that letter set.
letterSets[letterSet].add(c);
}
}
}
return letterSets;
}
int main() {
ifstream in;
int mSeed =0;
while (true) {
string fileName = getLine("Please enter a file name");
in.open(fileName);
if(in.fail()) cout << "Couldn't open file!" << endl;
else break;
}
// CountLetters(in);
while (true) {
mSeed=getInteger("Enter a seed value: ");
if (mSeed>0&&mSeed<=10) {
break;
} else {
cout << "Please choose a value from 1 to 10." << endl;
}
}
Map<string, Vector<char> > letterSets = assembleSets(in, mSeed);
Map<string, Vector<char> > :: iterator itr;
for (auto& it: letterSets) {
string keys = (it.first);
Vector<char> values = it.second;
}
return 0;
}
Any help would be fantastic! I'm really scratching my head.
It simply means that Map<string, Vector<char> > :: iterator.
Using std::map instead of Map and std::vector instead of Vector compiles correctly.
Check the implementation of your custom iterator.
Anyway i suggest you using the range-based syntax for this (if you use the C++ standard library):
for (auto& it : letterSets)
{
string key = it.first;
vector<char> values = it.second;
}
Beginner C++ student here, first ever programming class. I am trying to put together a program that will identify if a string is all lower case or not. I got as far as the code below. However, I need to account for spaces " ". If there is a space in the string that is input by the user, the program is suppose to return that it is not all lower case. Example:
input: abc def
return: The string is not lower case.
Would any of you ever so kindly advise what would be the best way to account for this in the code below?
NOTE: I know I have 'included' some extra header files, but that is because this is going to be part of another program and this is just an excerpt to get things running.
Thank you so very much all!!
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <iomanip>
using namespace std;
bool die(const string & msg);
bool allLower(const string & l);
int main() {
string l;
cout << "\nEnter a string (all lower case?): ";
cin >> l;
if (allLower(l) == true)
{
cout << "The string is lower case." << endl;
}
else
{
cout << "The string is not lower case." << endl;
}
}
bool allLower(const string & l) {
struct IsUpper {
bool operator()(int value) {
return ::isupper((unsigned char)value);
}
};
return std::find_if(l.begin(), l.end(), IsUpper()) == l.end();
}
bool die(const string & msg){
cout << "Fatal error: " << msg << endl;
exit(EXIT_FAILURE);
}
You could use a good old fashion for-loop.
bool allLower(const std::string & l)
{
for(unsigned int i = 0; i < l.size(); i++)
{
if(l[i] == ' ')
{
return false;
}
else if(isalpha(l[i]))
{
if(isupper(l[i]))
return false;
}
}
return true;
}
Note that if you feed it in something like "2" it will return true. You could add a final else statement that returns false if you so desire.
You can check to see if a character is alphabetic using the function std::isalpha() prior to using std::isupper() or std::islower() to checking whether all letters within your string are uppercase/lowercase, etc
A range-based for loop would be clearer than indices IMO
bool allLower(const std::string &l)
{
for (auto c : l)
{
if ((c == ' ') ||
(std::isalpha(c) && std::isupper(c)))
{
return false;
}
}
return true;
}
So I am creating an hangman game and want to add a char into a string. I want to add a char of guess to the gatherguess string until the gatherguess matches hangman. Feel free to add some helpful tips to my code that will make me better. Also if it would be more then nice if you can also give me some sample code with dynamic memory allocation.
#include <stdio.h>
#include <string.h>
#include <iostream> // std::cout
#include <stdio.h>
#include <string.h>
#include <iostream> // std::cout
#include <algorithm> // std::for_each
#include <vector>
#include <set>
#include <string>
bool isitdone(std::string foo, std::string hang){
return foo == hang ? true : false ;
}
int main(){
std::string hangman;
char guess;
std::string gatherguess; //Get the letters guessed.
std::cin >> hangman; //Player enter the word to guess.
bool checkstatement; // Check to see if game is over.
for(int i =0; i < 10; ++i) {
std::cin >> guess; //Individual characters to guess
std::string doo;
int wordsin;
doo = hangman;
int y;
if(doo.rfind(guess) != std::string::npos) {
std::cout << "Right " << guess << " Is in the word" << std::endl;
std::cout << std::endl;
checkstatement = isitdone(gatherguess,doo);// I want to add guess char into gatherguess
//then check to see if gatherguess is equal to the word then the game will be complete
if(checkstatement == true) {
return 0;
}
} else {
std::cout << "Wrong" << std::endl;
}
}
return 0;
}
First of all, you should initialize gatherguess with enough placeholder characters:
auto hangman = std::string{};
std::cin >> hangman;
auto gatherguess = std::string{hangman.size(), '_'};
Now you can simply overwrite the '_' characters.
auto pos = hangman.find(guess)
if(pos != std::string::npos) {
// ...
do {
gatherguess[pos] = guess; // overwrite
pos = hangman.find(guess, pos); // find next ocurrence
} while(pos != std::string::npos)
// ...
}
I made some changes on your code. It contains some pieces of advice as comment.
//#include <stdio.h> // Do not include a library if you don not use it, because it makes the performance worse.
//#include <string> // Do not include a library if you don not use it, because it makes the performance worse.
#include <iostream> // std::cout
//#include <stdio.h> // It is pointless to include a library twice.
//#include <string.h>
//#include <iostream> // std::cout
//#include <algorithm> // std::for_each
//#include <vector> // Do not include a library if you don not use it, because it makes the performance worse.
//#include <set> // Do not include a library if you don not use it, because it makes the performance worse.
#include <string>
bool isitdone(const std::string& foo, const std::string& hang){ // Passing argument by const reference makes performance much better.
return foo == hang ? true : false ; // Indenting makes the code much more readable.
}
int main(){
const int N=10; // Store constant number in constant variable, because you can change its' value later easily.
std::string hangman;
char guess;
std::string gatherguess; //Get the letters guessed.
std::cin >> hangman; //Player enter the word to guess.
bool checkstatement; // Check to see if game is over.
for(int i =0; i < N; ++i)
{
std::cin >> guess; //Individual characters to guess
std::string doo;
int wordsin;
doo = hangman;
int y;
if(doo.rfind(guess) != std::string::npos)
{
std::cout << "Right " << guess << " Is in the word" << std::endl;
std::cout << std::endl;
checkstatement = isitdone(gatherguess,doo);// I want to add guess char into gatherguess
//then check to see if gatherguess is equal to the word then the game will be complete
if(checkstatement == true)
{
return 0;
}
} else
{
std::cout << "Wrong" << std::endl;
}
}
return 0;
}
I think there is a logical mistake in your program. What happens if a word contains more than 10 different characters? Do not count if the tipp is right.
You can add a char to a string this way:
#include <iostream>
#include <string>
int main(){
std::string str="123";
str+='4';
std::cout<<str<<std::endl;
return 0;
}