Home > Back-end >  Find out which worker had the most working hours
Find out which worker had the most working hours

Time:12-29

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.

  1. 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.
  2. 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.

  • Related