My plan is to store a couple dozen rows with 2 items per row and both items will have a different data type. Not sure if this is the right approach and have heard about using vectors but I can't find any samples that will take in 2 items with different types with many rows (an unknown amount of rows) similar to what I'm trying to do here. The following doesn't compile
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct movies_t {
string title;
int year;
} myRecNo[];
void printmovie (movies_t movie);
int main ()
{
string mystr;
for (int i=0; i < 2; i++)
{
switch (i)
{
case 1:
myRecNo[i].title = "2001 A Space Odyssey";
myRecNo[i].year = 1968;
cout << "Auto entry is:\n ";
printmovie (myRecNo[i]);
break;
case 2:
myRecNo[i].title = "2002 A Space Odyssey";
myRecNo[i].year = 1978;
cout << "Auto entry is:\n ";
printmovie (myRecNo[i]);
break;
}
}
return 0;
}
void printmovie (movies_t movie)
{
cout << movie.title;
cout << " (" << movie.year << ")\n";
}
This is the error I get:
Test1.obj||error LNK2019: unresolved external symbol "struct movies_t * myRecNo" (?myRecNo##3PAUmovies_t##A) referenced in function _main|
There are a couple of bad practices in your code, if you are just asking for a way to modify the program so that it will compile and work, see the following:
Declare struct and create struct variables in your main function.
struct movies_t
{
string title;
int year;
};
then, in your main function, movies_t myRecNo[2];
Arrays start at index 0, not 1. so your switch should be
switch (i)
{
case 0:
myRecNo[i].title = "2001 A Space Odyssey";
myRecNo[i].year = 1968;
cout << "Auto entry is:\n ";
printmovie(myRecNo[i]);
break;
case 1:
myRecNo[i].title = "2002 A Space Odyssey";
myRecNo[i].year = 1978;
cout << "Auto entry is:\n ";
printmovie(myRecNo[i]);
break;
}
// the rest of the code..
After you modify these, your code should work.
However, for a better data structure to save an array of paired values, you can use std::vector<std::pair<string, int>> myReg to save your data.
the following code should be much much better, remember to #include <vector>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
void printmovie(std::vector<std::pair<std::string, int>>);
int main()
{
std::vector<std::pair<std::string, int>> myReg;
myReg.push_back({ "2001 A Space Odyssey", 1968 });
myReg.push_back({ "2002 A Space Odyssey", 1978 }); // <- if your compiler is not using c++11 standard or above, please change this line to myReg.push_back(std::pair<std::string, int>("name of the movie", int)); to use to older version of Initializer
printmovie(myReg);
return 0;
}
void printmovie(std::vector<std::pair<std::string, int>> movie)
{
for (auto itor = movie.begin(); itor != movie.end(); ++itor)
{
//first is the first data in the pair, which is the title
//second is the second data in the pair, which is the year
std::cout << (*itor).first << " (" << (*itor).second << ")\n";
}
}
Thanks everyone & #Zhou.
Zhou's code above might work on a newer version of the compiler but I'm using Code::Blocks IDE with MS Visual C++ 2010 compiler.
Here is the vector method that worked:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
void printmovie(std::vector<std::pair<std::string, int>>);
int main()
{
std::vector<std::pair<std::string, int>> myReg;
myReg.push_back(std::pair<std::string, int>("title of the movie", 1968));
myReg.push_back(std::pair<std::string, int>("title of the movie2", 1978));
//myReg.push_back({ "2001 A Space Odyssey", 1968 });
//myReg.push_back({ "2002 A Space Odyssey", 1978 });
printmovie(myReg);
//or to print a single element (the 2nd row) thanks #zhou
std::cout << myReg[1].first << " " << myReg[1].second << std::endl;
return 0;
}
void printmovie(std::vector<std::pair<std::string, int>> movie)
{
for (auto itor = movie.begin(); itor != movie.end(); ++itor)
{
//first is the first data in the pair, which is the title
//second is the second data in the pair, which is the year
std::cout << (*itor).first << " (" << (*itor).second << ")\n";
}
}
Related
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
void elimdups(vector<string>& words) {
sort(words.begin(), words.end());
for(auto a : words)
{
cout << a << " ";
}
cout << endl;
auto end_unique = unique(words.begin(), words.end());
for (auto a : words)
{
cout << a << " ";
}
cout << endl;
words.erase(end_unique, words.end());
for (auto a : words)
{
cout << a << " ";
}
cout << endl;
}
int main()
{
vector<string> kim = { "love", "peace", "horrible", "love", "peace", "hi", "hi" };
elimdups(kim);
return 0;
}
--
result:
hi hi horrible love love peace peace
hi horrible love peace love peace
hi horrible love peace
end_unique algorithm do not delete elements.
but on the second cout operation, "hi" disappear.
why "hi" disappear on the second line?
auto end_unique = unique(words.begin(), words.end());
for (auto a : words)
//...
Any items from [end_unique, words.end()) have unspecified values after the call to std::unique. That's why the output in the "erased" range seems strange.
If you want to preserve the "erased" words and keep the relative order, std::stable_partition with the appropriate lambda that checks duplicates could have been done.
I'm doing some rather simple code with set
#include <iostream>
#include <map>
#include <string>
#include <set>
using namespace std;
void printSol(map<string, string> parelles, const set<string>& sols) {
cout << "COUPLES:" << endl;
for (auto& x : parelles) {
cout << x.first << " " << x.second << endl;
parelles.erase(x.second);
}
cout << "ALONE:" << endl;
for (auto x : sols) {
cout << x << endl;
}
cout << "----------" << endl;
}
int main() {
map<string, string> parelles;
set<string> sols;
string inst, nom1, nom2;
while (cin >> inst) {
if (inst == "liats") {
cin >> nom1 >> nom2;
sols.erase(nom1);
sols.erase(nom2);
sols.insert(parelles[nom1]);
sols.insert(parelles[nom2]);
parelles.erase(parelles[nom1]);
parelles.erase(parelles[nom2]);
parelles[nom1] = nom2;
parelles[nom2] = nom1;
}
else if (inst == "info") {
printSol(parelles, sols);
}
}
}
For the input:
liats gerard shakira
liats sara iker
liats gerard sara
liats iker cristiano
info
It prints
COUPLES:
cristiano iker
gerard sara
ALONE:
shakira
----------
but should print
COUPLES:
cristiano iker
gerard sara
ALONE:
shakira
----------
But there is an extra endl after ALONE. I checked the size of the set and it's 2, and I don't really know what's going on. It seems like x has the null string.
Can someone point out in the right direction?
The map::operator[] strikes again. This operator inserts a value-initialized element if the key doesn't exist in the map. For string, this means it will insert an empty string. Here's a fix:
// sols.insert(parelles[nom1]);
// sols.insert(parelles[nom2]);
auto it = parelles.find(nom1);
if (it != parelles.end()) sols.insert(it->second);
it = parelles.find(nom2);
if (it != parelles.end()) sols.insert(it->second);
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
struct StudentDataTypes
{
std::string name{};
int grade{};
};
int main()
{
//Ask for Class_Size
int Class_Size{};
std::cout << "How big is the class?" << '\n';
std::cin >> Class_Size;
//Syntax format
//std::vector<T> array(size);
//Intialize a vector for the students called Vector_Student
//T links to the struct StudentDataTypes
//size is the Class_Size.
std::vector<StudentDataTypes> Vector_Student(Class_Size);
//Print Class Size
std::cout << "There are " << Class_Size << " students." << '\n';
//Get the Userinputs for the Class
for (int i = 0; i < Class_Size; ++i)
{
std::cout << "Please input the name of Student #" << i + 1 << '\n';
std::cin >> Vector_Student[i].name;
std::cout << "Please input the grade of Student #" << i + 1 << '\n';
std::cin >> Vector_Student[i].grade;
}
//Sort
std::sort(Vector_Student.begin(), Vector_Student.end());
//Print the required output
for (int j = 0; j < Class_Size; ++j)
{
std::cout
<< Vector_Student[j].name
<< " got a grade of "
<< Vector_Student[j].grade << '\n';
}
return 0;
}
I have an issue with a Vector Struct tutorial.
I'm using Visual Studio 2019 and there's a peculiar scenario where the compiler doesn't give me any warning at all. If I debug it, the first warning appears on line 1544, way out of bounds. The above code will actually sort of compile, run and crash.
I know the issue lies in the sorting but I can't figure it out.
std::sort requires you to implement operator< for your datatype. Here in this case adding following definition in your class will get your code to compile
bool operator<(const StudentDataTypes& that) {
return this->grade < that.grade;
}
Update:
Alternatively as sugested by Casey, we can use custom sort comparator. Here is the sample code for the same.
std::sort(Vector_Student.begin(), Vector_Student.end(), [](const StudentDataTypes& a, const StudentDataTypes&b) { return a.grade < b.grade; });
Here is the answer. I'm posting it in the answers for how to sort a vector-struct.
Step 1:
bool compareTwoStudents(StudentDataTypes a, StudentDataTypes b) {
if (a.grade != b.grade)
return a.grade > b.grade;
return a.grade==b.grade;
}
Step 2:
std::sort(Vector_Student.begin(), Vector_Student.end(),compareTwoStudents);
Okay so I have a programming project due in about 7 minutes. My project reads a double GPA and a string Name in a txt file. I correctly place the GPA and Names into separate STL lists for the project. My problem comes when I try to push the highest GPA value into a queue. At that point it gives the error that no instance of overloaded function.
Since I am using pointers, I have tried different methods of using pointers but to no avail. I figure that pointers might be a part of the problem.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <list>
#include <queue>
using namespace std;
//using std::because it says cout is ambiguous even with std included
int main()
{
double GPA;
double highestGPA;
string name;
list<double> listGPA; //lists and their iterators
//list<double>::iterator ptrGPA, ptrHighestGPA;
double *ptrGPA, *ptrHighestGPA;
list<string> listName;
//list<string>::iterator ptrName, ptrHighestName;
string *ptrName, *ptrHighestName;
queue<double> queueGPA; //queues
//queueGPA.front() = 0;
queue<string> queueName;
//queueName.front() = "";
ifstream infile;
infile.open("HighestGPAData.txt");
if (!infile) //if file doenst exist
{
std::cout << "The input file does not "
<< "exist. Program terminates!"
<< endl;
std::system("pause");
return 1;
}
std::cout << fixed << showpoint;
std::cout << setprecision(2);
infile >> GPA >> name;
while (infile) { //place contents of file into 2 STL lists
listGPA.push_back(GPA);
listName.push_back(name);
infile >> GPA >> name;
}
std::cout << "\nSTL list for GPA:\n";
for (auto g : listGPA) { //range based for loop that prints GPA list
std::cout << g << "\n";
}
std::cout << "\nSTL list for names:\n";
for (auto s : listName) { //range based for loop that prints name
std::cout << s << "\n";
}
std::system("pause");
ptrGPA = &listGPA.front(); //initialize pointers for each list
ptrHighestGPA = ptrGPA;
ptrName = &listName.front();
ptrHighestName = ptrName;
while (!listGPA.empty()) // there are two lists (name and GPA)
if (ptrGPA > ptrHighestGPA) {
while (!queueGPA.empty()) { //destroy queue i (so a lower
queueGPA.pop();
}
while (!queueName.empty()) { //destroy queue if a higher //gpa is found (so a lower gpa is not printed)
queueName.pop();
}
/***********************problem here */
ptrHighestGPA = ptrGPA;
queueGPA.push(ptrHighestGPA); //add to queue if it is
ptrHighestName = ptrName;
queueName.push(ptrHighestName);
}
else if (ptrGPA == ptrHighestGPA) { //add to the queue ifcurrent gpa
queueGPA.push(ptrHighestGPA);
queueName.push(ptrHighestName);
}
/* end problem */
listGPA.pop_front();
listName.pop_front();
ptrGPA++;
ptrName++; //= listName.front();
}
while (!queueGPA.empty()) { //print the largest gpa.
std::cout << queueGPA.front() << " ";
queueGPA.pop();
}
std::cout << "\n";
while (!queueName.empty()) { //print who has the highest gpa
std::cout << queueName.front() << " ";
queueName.pop();
}
std::system("pause");
return 0;
}
Currently it outputs both lists but I can easily comment that out. I want the queues queueName and queueGPA to contain the highest GPA and name associated with that GPA from the lists listGPA and listName.
Thank you guys
I have to read two text files and then compare words from second file with the first one. Then , I have to display KnownWords which are same words from both files and the remaining words which are not same are UnknownWords. Next Step is, I have to display most frequent known words in DisplayMostFreqKnownWords() and unknown words in DisplayMostFreqUnknownWords() functions. I have successfully completed DisplayMostFreqKnownWords() and so far Output is alright. I copied the same code from DisplayMostFreqKnownWords() to DisplayMostFreqUnknownWords() but in this is function it is not showing anything in the output. I dont know what is wrong. Can someone figure this one out.
Output is:
Displaying most frequent known words
Word Count
the 19
a 14
of 11
artificial 11
that 10
to 7
signal 7
and 7
in 6
they 5
Displaying most frequent unknown words
Word Count
Header file:
typedef map<string, vector<int> > WordMap;
typedef WordMap::iterator WordMapIter;
class WordStats
{
public:
WordStats();
void ReadDictionary();
void DisplayDictionary();
void ReadTxtFile();
void DisplayKnownWordStats();
void DisplayUnknownWordStats();
void DisplayMostFreqKnownWords();
void DisplayMostFreqUnknownWords();
private:
WordMap KnownWords;
WordMap UnknownWords;
WordMapIter Paragraph;
set<string> Dictionary;
char Filename[256];
}
My program:
// Displays 10 most frequent words in KnownWords
void WordStats::DisplayMostFreqKnownWords(){
int count;
multimap<int,string > displayFreqWords;// new map with int as key
(multimap because key could occur more than once)
multimap<int,string >::reverse_iterator rit = displayFreqWords.rbegin();
for (Paragraph = KnownWords.begin(); Paragraph != KnownWords.end();
++Paragraph){ // iterate map again
string word = (*Paragraph).first;
int cnt = (*Paragraph).second.size();
displayFreqWords.insert(pair<int,string>(cnt,word));
}
// multimap<int,string>::iterator rit; // iterator for new map
cout <<" Word Count\n";
for(; count<=10 && rit!=displayFreqWords.rend(); rit++, ++count){
string word = (*rit).second;
int cnt = (*rit).first;
cout << setw(15) << word << setw(10) << cnt << endl;
}
}
// Displays 10 most frequent words in UnknownWords
void WordStats::DisplayMostFreqUnknownWords(){
int count;
multimap<int,string > displayFreqUnknownWords;
multimap<int,string >::reverse_iterator rrit =
displayFreqUnknownWords.rbegin();
for (Paragraph = UnknownWords.begin(); Paragraph !=
UnknownWords.end(); ++Paragraph){
string word = (*Paragraph).first;
int cnt = (*Paragraph).second.size();
displayFreqUnknownWords.insert(pair<int,string>(cnt,word));
}
// multimap<int,string>::iterator rit; // iterator for new map
cout <<" Word Count\n";
for(; count<=10 && rrit!=displayFreqUnknownWords.rend(); rrit++, ++count){
string wrd = (*rrit).second;
int ccnt = (*rrit).first;
cout << setw(15) << wrd << setw(10) << ccnt << endl;
}
}
Here's a way to express what I think is your use case. I have used c++17 tuple expansion.
I have used unordered_map to deduce which words are known or unknown, and two multimaps to determine known and unknown word frequency.
Hope it's helpful.
#include <sstream>
#include <tuple>
#include <string>
#include <unordered_map>
#include <algorithm>
#include <iterator>
#include <map>
#include <iostream>
#include <iomanip>
#include <fstream>
// Set this to 1 to run a static test
#define TESTING 0
#if TESTING
using input_type = std::istringstream;
std::tuple<input_type, input_type> open_inputs() {
return {
std::istringstream("the big black cat sat on the grey mat"),
std::istringstream("the gold small cat lay on the purple mat")
};
}
#else
using input_type = std::ifstream;
std::tuple<input_type, input_type> open_inputs() {
return {
std::ifstream("left_file.txt"),
std::ifstream("right_file.txt"),
};
}
#endif
struct Counts {
int left_count = 0, right_count = 0;
int total() const {
return left_count + right_count;
}
bool is_known() const {
return left_count && right_count;
}
};
template<class F>
void for_each_word_in_file(std::istream &is, F f) {
std::for_each(std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>(),
f);
}
int main() {
// open files
auto[left, right] = open_inputs();
auto known_words = std::unordered_map<std::string, Counts>();
// count words in each file
for_each_word_in_file(left, [&known_words](auto &&word) {
++known_words[word].left_count;
});
for_each_word_in_file(right, [&known_words](auto &&word) {
++known_words[word].right_count;
});
// map counts to words, in descending order, allowing multiple entries of the same count
std::multimap<int, std::string, std::greater<>> known_ordered, unknown_ordered;
// iterate all words seen, putting into appropriate map
for (auto&&[word, counts] : known_words) {
(counts.is_known() ? known_ordered : unknown_ordered)
.emplace(counts.total(), word);
}
// emit results
std::cout << "Known words by frequency\n";
for (auto&&[freq, word] : known_ordered) {
std::cout << std::setw(15) << word << " " << freq << '\n';
}
std::cout << "\nUmknown words by frequency\n";
for (auto&&[freq, word] : unknown_ordered) {
std::cout << std::setw(15) << word << " " << freq << '\n';
}
}