2
\$\begingroup\$

Doubts in logic to generate the output file according to the example I need that even if he reaches the total_min <720 condition he continues to travel the lines. 720 is the total number of minutes before lunch, when reached, it should separate the activities that should be performed after lunch (lunch must be inserted manually).

  • I need to make a system that reads a TXT file (intput.txt).
  • This file has several lines.
  • Each line an activity with execution time (30min, 45min, 60min)
  • Activities should start at 9 am.
  • Half day (12:00) lunch break
  • Generate a TXT with organized activities (output.txt)

intput.txt

Correr 60min
Estudar 30min
Ler 45min
Escrever 60min
Caminhar 45min
Jogar 30min

Example how the output.txt file should look

09:00 Correr 60min
10:00 Estudar 30min
10:30 Ler 45min
11:15 Caminhar 45min
12:00 Almoço 60min
13:00 Jogar
(...)

My code:

    public static void main(String[] args) throws IOException {
    // TODO code application logic here

    ArrayList<String> antes_almoco = new ArrayList<String>();
    ArrayList<String> depois_almoco = new ArrayList<String>();

    int total_min = 540;
    int horas = total_min / 60;
    int minutos = total_min % 60;
    String trinta = "30min";
    String quarentaCinco = "45min";
    String sessenta = "60min";
    boolean trinta_min = false;
    boolean quarentaCinco_min = false;
    boolean sessenta_min = false;
    String path = "C:\\input.txt";
    String outputDir = "C:\\output.txt";

    FileReader arq = new FileReader(path);
    BufferedReader lerArq = new BufferedReader(arq);
    String linha;

    //Output   
    File file2 = new File(outputDir);
    FileWriter arq_output = new FileWriter(file2, true);
    PrintWriter gravarArq = new PrintWriter(arq_output);

    if (!file2.exists()) {
        file2.createNewFile();
    }

    while ((linha = lerArq.readLine()) != null) {

        trinta_min = linha.toLowerCase().contains(trinta.toLowerCase());
        quarentaCinco_min = linha.toLowerCase().contains(quarentaCinco.toLowerCase());
        sessenta_min = linha.toLowerCase().contains(sessenta.toLowerCase());

        if (sessenta_min == true) {
            total_min += 60;
            if (total_min < 720) {
                antes_almoco.add(linha);
            } else if (total_min > 720) {
                depois_almoco.add(linha);
            }
        }

        if (trinta_min == true && total_min < 720) {
            total_min += 30;
            if (total_min < 720) {
                antes_almoco.add(linha);
            } else if (total_min > 720) {
                depois_almoco.add(linha);
            }
        }

        if (quarentaCinco_min == true && total_min < 720) {
            total_min += 45;
            if (total_min < 720) {
                antes_almoco.add(linha);
            } else if (total_min > 720) {
                depois_almoco.add(linha);
            }
        }

        if (total_min == 720) {
            total_min += 60;
            antes_almoco.add("12:00 Almoço");
        }
    }

    for (String cont : antes_almoco) {
        System.out.println(cont);
        gravarArq.printf("%d:%02d %s \n", horas, minutos, cont);
    }
    for (String cont : depois_almoco) {
        //System.out.println(cont);
        gravarArq.printf("%d:%02d %s \n", horas, minutos, cont);
    }
    lerArq.close();
    gravarArq.close();
    arq.close();
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Can you clarify the question? Are you just looking for a general code review, or is there a problem? \$\endgroup\$ – tomtzook May 16 at 4:01
  • \$\begingroup\$ (lunch must be inserted manually I hate the vision of being machine (force) fed.) \$\endgroup\$ – greybeard May 16 at 5:31
  • \$\begingroup\$ (720 is the total number of minutes & start at 9 am. Half day (12:00) lunch break is that working surprisingly short minutes, or looong hours?) \$\endgroup\$ – greybeard May 16 at 5:36
  • \$\begingroup\$ I see neither lunch inserted manually nor horas or minutos computed/updated: I don't see how this can possibly work: off topic at CodeReview@SE. \$\endgroup\$ – greybeard May 16 at 5:46
  • 2
    \$\begingroup\$ 720 minutes is 12 hours, not 3 hours. It's 180 minutes from 9 am to 12 noon. An entire conference day is 6 or 7 hours (360 or 420 minutes) at most. @greybeard made a joke, but there's something wrong with your instructions. \$\endgroup\$ – Gilbert Le Blanc May 16 at 15:13
3
\$\begingroup\$

I revised your code and ran some tests.

Here is the input to my last test.

Correr 60min
Estudar 30min
Ler 45min
Escrever 60min
Caminhar 45min
Cutting of steel sheets 60min
Jogar 30min

Here is the output from my last test.

09:00 Correr 60min
10:00 Estudar 30min
10:30 Ler 45min
11:15 Escrever 60min
12:15 Almoço 60min
01:15 Caminhar 45min
02:00 Cutting of steel sheets 60min
03:00 Jogar 30min

The first major change I made to your code was to write a method to convert elapsed minutes to time.

I only needed one List to hold the events. Actually, I didn't need the List at all. I could have written the string out as I created it, but I left the List in.

I also simplified the processing of each line. All I need is the number of minutes that the event lasts. This code can handle any number of minutes, not just 30, 45, or 60.

Edited to add: I revised the code to handle an input line with an event that has spaces in the event text.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

public class Schedule {

    public static void main(String[] args) throws IOException {
        // TODO code application logic here

        List<String> events = new ArrayList<>();

        String path = "C:\\Eclipse\\Eclipse-2020-workspace\\"
                + "com.ggl.testing\\resources\\input.txt";
        String outputDir = "C:\\Eclipse\\Eclipse-2020-workspace\\"
                + "com.ggl.testing\\resources\\output.txt";

        FileReader arq = new FileReader(path);
        BufferedReader lerArq = new BufferedReader(arq);

        // Output
        File file2 = new File(outputDir);
        FileWriter arq_output = new FileWriter(file2, true);
        PrintWriter gravarArq = new PrintWriter(arq_output);

        if (!file2.exists()) {
            file2.createNewFile();
        }

        int totalMinutes = 0;
        int lunchMinutes = 180;
        boolean beforeLunch = true;

        String linha;
        while ((linha = lerArq.readLine()) != null) {
            String[] fields = linha.split(" ");
            int lastIndex = fields.length - 1;
            int endIndex = fields[lastIndex].lastIndexOf("min");
            int duration = Integer.valueOf(
                    fields[lastIndex].substring(0, endIndex));

            String output = "";
            for (int i = 0; i < fields.length; i++) {
                output += fields[i] + " "; 
            }
            output = toTime(totalMinutes) + " " + output;
            events.add(output.trim());

            totalMinutes += duration;

            if (beforeLunch && totalMinutes >= lunchMinutes) {
                output = toTime(totalMinutes) + " Almoço 60min";
                events.add(output);
                totalMinutes += 60;
                beforeLunch = false;
            }
        }

        for (String cont : events) {
            System.out.println(cont);
            gravarArq.println(cont);
        }

        lerArq.close();
        gravarArq.close();
        arq.close();
    }

    private static String toTime(int minutes) {
        int hours = minutes / 60 + 9;
        hours = hours % 12;
        hours = (hours == 0) ? 12 : hours;
        minutes = minutes % 60;
        return String.format("%02d:%02d", hours, minutes);
    }

}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thank you Gilbert! The following error is returning to me:Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: -1 at java.lang.String.substring(String.java:1967) Is it an error reading the String? \$\endgroup\$ – Ronison Matos May 16 at 16:14
  • \$\begingroup\$ @RonisonMatos: Does the input current line have "min" at the end? Is there a space between the name and the duration? \$\endgroup\$ – Gilbert Le Blanc May 16 at 16:16
  • \$\begingroup\$ It has "min", but the number of characters in the line is greater. Follows current first line. Cutting of steel sheets 60min. if I put Correr 60min it works \$\endgroup\$ – Ronison Matos May 16 at 16:26
  • 1
    \$\begingroup\$ @RonisonMatos: I wasn't aware that event text could contain spaces. See my revised answer. \$\endgroup\$ – Gilbert Le Blanc May 16 at 16:41
  • \$\begingroup\$ Worked perfectly! Thank you! \$\endgroup\$ – Ronison Matos May 16 at 16:49
3
\$\begingroup\$
ArrayList<String> antes_almoco = new ArrayList<String>();
ArrayList<String> depois_almoco = new ArrayList<String>();
  1. You should use the lowest common denominator that you always need, in this case you should declare the variables as List<String>, as you most likely don't need to bind yourself to a specific implementation.
  2. Java naming conventions are lowerCamelCase for variables.

int horas = total_min / 60;

Not a problem here, but be aware that dividing an integer by an integer will always yield an integer:

double value = 5 / 2;
// value == 2.0

String path = "C:\\input.txt";
String outputDir = "C:\\output.txt";

You could make those relative to the jar, so this application would also run on non-Windows systems.

Also, the variable name is wrong, it's not a directory.

Also also, declare variables when they are needed, not all of them on the start of the block. It allows you to limit variables to certain scopes and makes refactoring easier as everything that belongs together is together.


FileReader arq = new FileReader(path);

"Native" resources like files, sockets, etc. require a well-defined lifecycle so that they are correctly freed when not needed anymore. You can use the try-with-resources for that or call close on the resources you don't need anymore.

FileReader reader = new FileReader(path);

// Application logic.

reader.close();
try (FileReader reader = new FileReader(path)) {
    // Logic.
} // close being called automatically when leaving the block.

There is the java.time API, especially the Duration class which seems to be highly applicable to your use-case.

Now what you could do with this is, to split it into functions and classes. That would be a good exercise. A good start for that would be to extract the representation of a single line to a class, like this:

// All time-classes from java.time.

public class TimeEntry {
    public TimeEntry(LocalTime startTime, String name, Duration duration);
    public static TimeEntry create(String stringRepresentation);
    @Override
    public String toString();
    // Getters for these values.
}

The create Method is a factory method which parses the string representation as in the file and outputs a valid TimeEntry class or null. The toString returns the string representation as in the file.

That means that your loop can be basically summed up as:

for (String line : lines) {
    TimeEntry timeEntry = TimeEntry.create(line);

    if (timeEntry != null) {
        doLogicOnIt(timeEntry);
    }
}

Also you should separate reading from writing. There are times when you want to do both at the same time, but to exercise separation I'd suggest to read the file in one function that returns a List of TimeEntrys, then there is another function manipulating that list and and a third writing it to a file. That has the upside that you can read and write the files faster, you're not bound to the files as input/output source and you can easier control the lifecycle of the file handles.

Now, there are times when reading everything into memory is inappropriate. That is when you either have a pipe as input, or if the state you're reading from the file is too large to keep in memory. Neither is the case here.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.