The problem goes something like this. Given the number "n", on the next "n" lines you will find texts similar to " Worker "x" has worked "y" hours this month". "x" and "y" are numbers from 1 to 10000. If a worker appears multiple times in the list, sum up the hours. At the end print the index number of the worker with the most hours worked.
For ex:
3
Worker 23 worked 5 hours.
Worker 5 worked 10 hours.
Worker 23 worked 7 hours.
The output will be: 23.
I read de file like this:
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
char s[50];
int n;
int main() {
ifstream fin("date.in");
fin >> n;
fin.getline(s, 50);
for (int i = 0; i < n; i) {
fin.getline(s, 50);
}
return 0;
}
My problem is that I cannot differentiate "x" from "y". Can anyone give me an idea to how to start the problem?
CodePudding user response:
You can decompose a line with std::istringstream
.
Example:
std::string line = "Worker 23 worked 5 hours.";
std::string word;
int id = 0;
int time = 0;
std::istringstream is(line);
if (is >> word >> id >> word >> time)
{
...
do whatever with 'id' and 'time'
...
}
CodePudding user response:
There are two main approaches to solve this problem.
- If you are learning C and do not know the language and its algorithm that good, then you need to go the hard way and do everything by yourself.
- If you are an experienced developer, then you can use the full power of C . This will result in a compact solution, but you need to learn a while to understand it.
Whatever, I will show you a poetntial soultion for both approaches.
Number 1. We will use only every basic C language and as less library functions as possible. We will even not use a std::string
or a std::vector
, which is basically a "must have" here.
What will be do?
- Open the file
- Read line by line in a string (char array)
- Scan the char array character by character to find the numbers (id, hours)
- Check, if a worker already existed. If yes, add up, if no, create a new one. Use 2 arrays for that.
- Last but not least, find the max element
This is a horrible work with a lot of programming . . .
Please see:
#include <iostream>
#include <fstream>
#include <iomanip>
// The format of the line is know. A length of 100 will be sufficient for the given use cases.
const int MaxLineLength = 50;
int main() {
// Open the source file
std::ifstream fin("r:\\date.in");
// Check, if the file could be opened
if (fin) {
// This will contain the content of one line in the source file
char lineText[MaxLineLength];
// Now, read the number of lines that we shall process
int numberOfLinesToProcess = 0;
// Read a number, check, if that works and check for a valid range (>0)
if ((fin >> numberOfLinesToProcess >> std::ws) and (numberOfLinesToProcess > 0)) {
// We will now waste some space and create space for numberOfLinesToProcess
// although we know, that there moste likely are duplicates
int* workerID = new int[numberOfLinesToProcess];
int* numberOfHours = new int[numberOfLinesToProcess];
// We need a counter to detect the differnt workers
int differentWorkersCount = 0;
// Now read line by line from the source file
for (int lineIndex = 0; lineIndex < numberOfLinesToProcess and fin; lineIndex) {
// Read one complete line fomr the file
fin.getline(lineText, MaxLineLength);
// Check, if the input function worked OK
if (fin) {
// Here will store the temporary extracted values
int wID = 0, whours = 0;
// We are looking for a number and will skip the text
bool waitForNumberToStart = true;
char* startOfNumber = nullptr;
bool waitForWorkerID = true;
// Now, iterate over the string and find digits, the worker ID
for (char* cptr = &lineText[0]; *cptr != '\0'; cptr) {
// Check, if we found a digit
if (waitForNumberToStart) {
if (*cptr >= '0' and *cptr <= '9') {
// First time taht we saw a digit. Remember start position in string
startOfNumber = cptr;
// Now we wait no longer for a number to start. We wait for the end
waitForNumberToStart = false;
}
}
else {
// We found a digit and now wait for the end of the number, so a none-digit
if (not (*cptr >= '0' and *cptr <= '9')) {
if (waitForWorkerID) {
wID = std::atoi(startOfNumber);
waitForWorkerID = false;
}
else {
whours = std::atoi(startOfNumber);
break;
}
waitForNumberToStart = true;;
}
}
}
// Now, we have read both numbers. The worker IS and the working hours.
// Check, if we saw this worker already
bool workerFound = false;
for (int i = 0; i < differentWorkersCount and not workerFound; i) {
// Check, if such a worker already exists
if (workerID[i] == wID) {
// Yes, worker did exists, add working hours.
numberOfHours[i] = whours;
workerFound = true;
}
}
// If the worker did not yet exist, then we create a new one
if (not workerFound) {
// Cearte a new worker at the end of the array
workerID[differentWorkersCount] = wID;
numberOfHours[differentWorkersCount] = whours;
// Now we have one worker more
differentWorkersCount;
}
}
else {
// Problem while reading
std::cout << "\nError: Problem while reading\n";
break;
}
}
// So, now we have found all workers and summed up all hours
// Search for max working time
int indexForMax = 0;
int maxWorkingTime = 0;
// Check all workers
for (int i = 0; i < differentWorkersCount; i) {
// Did we find a new max?
if (numberOfHours[i] >= maxWorkingTime) {
// If yes, then remeber this new may and remeber the workers index
maxWorkingTime = numberOfHours[i];
indexForMax = i;
}
}
// Now, we found everything and can show the result
std::cout << "Max: Worker: " << workerID[indexForMax] << " with: " << numberOfHours[indexForMax] << " hours\n";
// Release memory
delete[] workerID;
delete[] numberOfHours;
}
else {
// Invalid file content
std::cout << "\nError: Invalid file content\n";
}
}
else {
// The file could not be opened. Show error message
std::cout << "The source file yould not be opened\n";
}
}
Yes, indeed, the above works of course, but you really need to write a lot of code.
Modern C will help you here a lot. For many problems, we have ready-to-use functions.
Then the code will be rather compact in the end.
Please see:
#include <iostream>
#include <fstream>
#include <iomanip>
#include <unordered_map>
#include <algorithm>
using Sum = std::unordered_map<int, int>;
namespace rng = std::ranges;
int main() {
// Open file and check, if it could be opened
if (std::ifstream ifs{ "r:\\date.in" }; ifs) {
Sum data{};
// Read number of entries to operate on. We will ignore this value, we do not need it
if (int numberOfEntries{}; (ifs >> numberOfEntries >> std::ws)) {
// For reading the text and throwing away
std::string dummy;
// Read all lines and add up
for (int id{}, hours{}; ifs >> dummy >> id >> dummy >> hours >> dummy; data[id] = hours);
}
// Get max
const auto& [worker, hours] = *rng::max_element(data, {}, &Sum::value_type::second);
// Show result
std::cout << "Max: Worker: " << worker << " with: " << hours << " hours\n";
}
else std::cerr << "\n*** Error: Could not open souirce file\n";
}
Also many intermediate solutions are possible.
This depends on how much you learned already.