Reputation: 95
I was given a following task: create a text file which contains men, women and unknown names. Try to implement a filter that will compare those names with real names (so 3 files on input in total: men, women and let's say renters). While filtering put matching names in their appropriate containers. It seemed to me pretty straight forward so I did it the way I provide underneath.
My question is: Is there a way how to optimize this code?
I tried to use abstract classes and create 4 different objects (Man, Woman, Known, Unknown) based on abstract entity. But the amount of code was still large for such a simple task. Another idea was to use lambda expressions, but I am limited to C++ 98 only.
I think I am overthinking it...
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::ifstream men("resources/men_names.txt");
std::ifstream women("resources/women_names.txt");
std::ifstream renters("resources/renter_names.txt");
std::vector<std::string> menNames;
std::vector<std::string> womenNames;
std::vector<std::string> renterNames;
std::vector<std::string> knownRenters;
std::vector<std::string> unknownRenters;
std::string name;
while (men >> name)
menNames.push_back(name);
men.close();
while (women >> name)
womenNames.push_back(name);
women.close();
while (renters >> name)
renterNames.push_back(name);
renters.close();
std::vector<std::string>::iterator itMen;
std::vector<std::string>::iterator itWomen;
std::vector<std::string>::iterator itRenters;
for (itRenters = renterNames.begin(); itRenters != renterNames.end(); itRenters++)
{
bool found = false;
for (itMen = menNames.begin(); itMen != menNames.end(); itMen++)
{
if ((*itMen) == (*itRenters))
{
found = true;
knownRenters.push_back((*itMen));
}
}
if (!found)
{
for (itWomen = womenNames.begin(); itWomen != womenNames.end(); itWomen++)
{
if ((*itWomen) == (*itRenters))
{
found = true;
knownRenters.push_back((*itWomen));
}
}
}
if (!found)
unknownRenters.push_back((*itRenters));
}
std::cout << knownRenters.size() << '\n';
std::cout << unknownRenters.size() << '\n';
std::cin.get();
return 0;
}
Upvotes: 0
Views: 202
Reputation: 67723
You don't care whether a renter is male or female, just if they have a recognised name. So, don't store two flat vectors of known names, store a single std::set<std::string>
of all recognised names (or a sorted vector, or a std::unordered_set
if you're ever allowed to use C++11).
Then, instead of doing (at most) two linear searches per renter, you can do a single logarithmic-time lookup (or constant-time for the C++11 version).
You also don't seem to care about the names of the renters who were recognised (or not), so don't keep two result vectors: just increment a known
or unknown
counter.
Upvotes: 0
Reputation: 62656
A shortening of your existing code. This should be all C++98
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include <set>
#include <iterator>
int main()
{
std::ifstream men("resources/men_names.txt");
std::ifstream women("resources/women_names.txt");
std::set<std::string> peopleNames;
peopleNames.insert(std::istream_iterator<std::string>(men), std::istream_iterator<std::string>());
peopleNames.insert(std::istream_iterator<std::string>(women), std::istream_iterator<std::string>());
std::ifstream renters("resources/renter_names.txt");
std::vector<std::string> knownRenters;
std::vector<std::string> unknownRenters;
for (std::string name; renters >> name; )
{
if (peopleNames.count(name))
knownRenters.push_back(name);
else
unknownRenters.push_back(name);
}
std::cout << knownRenters.size() << '\n';
std::cout << unknownRenters.size() << '\n';
std::cin.get();
return 0;
}
Upvotes: 1