I will need to parse thousands upon thousands of simple entries in C . I've only ever programmed in C, so I might be missing some higher functions to make this task easier.
An entry consists of 4 separate values: a sender
, a receiver
, a date
, and a type of mail
. Three of these are string
values, the last one is an integer
. My goal (after all entries are processed) is to print out all different entries that were received on the input and how many times each of these entries were received.
That means that if there was the same sender, receiver, date, and type of mail, multiple times on the input, the output would say that this entry was received e.g 5 times.
What would be the best way to do this? I tried C map
but was unable to make it work.
CodePudding user response:
You might store it in a set / multiset, using a struct that implements comparison:
struct Entry {
friend bool operator<(const Entry& lhs, const Entry& rhs) {
if (lhs.sender < rhs.sender) return true;
if (lhs.sender > rhs.sender) return false;
if (lhs.receiver < rhs.receiver) return true;
if (lhs.receiver > rhs.receiver) return false;
if (lhs.date < rhs.date) return true;
if (lhs.date > rhs.date) return false;
if (lhs.type_of_mail < rhs.type_of_mail) return true;
return false;
}
std::string sender;
std::string receiver;
std::string date; // this should be a proper date time, otherwise DST & timezones might be a problem
int type_of_mail; // this should be enum
};
int main() {
std::set<Entry> entries;
// or
std::multiset<Entry> entries_duplications_allowed;
// you might insert elements here
// you might loop over entries using e.g. range for here
}
CodePudding user response:
I suggest defining a class with an operator<
that makes it possible to store instances of the class in a std::map
. The std::map
can be used to map from objects comparing equal to a count. Objects are considered equal if neither lhs < rhs
nor rhs < lhs
is true so only the operator<
overload is necessary.
You could also add operator>>
and operator<<
overloads to make it possible to read and write objects from streams.
It could look like this:
#include <iostream>
#include <map>
#include <string>
#include <tuple>
struct foo {
std::string sender;
std::string receiver;
std::string date;
int type_of_mail;
// compare two foo instances:
bool operator<(const foo& rhs) const {
return std::tie(sender, receiver, date, type_of_mail) <
std::tie(rhs.sender, rhs.receiver, rhs.date, rhs.type_of_mail);
}
// read a foo from an istream:
friend std::istream& operator>>(std::istream& is, foo& f) {
return is >> f.sender >> f.receiver >> f.date >> f.type_of_mail;
}
// write a foo to an ostream:
friend std::ostream& operator<<(std::ostream& os, const foo& f) {
return os << f.sender << ' ' << f.receiver << ' ' << f.date << ' '
<< f.type_of_mail;
}
};
int main() {
std::map<foo, unsigned> counts;
foo tmp;
// read foos from any istream
while(std::cin >> tmp) {
counts[tmp]; // count
}
// print the count for each
for(const auto&[f, count] : counts) {
std::cout << count << ' ' << f << '\n';
}
}
CodePudding user response:
I recommend a single data table along with an index table for each field you want to search. (Actually this smells like you should be using a database, rather than writing one)
Place all your records into a std::vector<Record>
.
Create a std::map<key_text, vector_index>
for each key field.
To find a record:
- Search the appropriate
map
(index table) with the key (string). - If found, extract the index field.
- Use the index filed for the
std::vector<Record>
.
Multiple field key search is more difficult and may take up more room (if you are using an indexing data structure).
IMHO, your best route is to use a database.