Search code examples
javafor-looptexthashmapprocessing

How do I pull text into a hashmap as an arraylist value for a specific key in a file in java


I have a text file which contains multiple titles and descriptive text below each title. I am trying to add each title to a hashmap key and the descriptive text to the value but cannot figure out how to iterate over this text file and properly parse the information. The title will ALWAYS contain an empty line before and after the title (unless it is the first line) and the value will ALWAYS be the text immediately after the respective title UNTIL the next title is reached in the file. The user will be given a list of keys to choose from in the program and the corresponding value will be printed.

Example Text File

Title

text
text
text

text
text

Title

text
text
text
text

The text file has multiple titles in the file and must be a single file.

Code

  private static HashMap<String, ArrayList<String>> hashmap = new HashMap<>();
  public static void processTextFile(ArrayList array) {
//Place first line in hashmap key
    hashmap.put((String) array.get(0), new ArrayList<>());
//Iterate over text file and add titles which have null spaces before and after as a key
    for (int i = 0; i < array.size(); i++) {
      if (array.get(i).equals("") && array.get(i + 2).equals("")) {
        hashmap.put((String) array.get(i + 1), new ArrayList<>());
      }
    }
  }

Desired Result

Please select a Title:
*user types a specific title*
Title

text
text
text

text
text

Solution

  • Assuming that there would be no single-line paragraphs (that can be confused with a title) and you don't need to store empty strings (if you need them remove the condition if (!list.get(i).isEmpty())), you can apply the following logic to populate the map with titles used a keys and Lists containing lines of text as values:

    private static Map<String, List<String>> textByTitle = new LinkedHashMap<>();
    
    public static void processText(List<String> list) {
        List<String> text = new ArrayList<>(); // text
        textByTitle.put(list.get(0), text);    // the first line is treated as a title
        
        for (int i = 1; i < list.size(); i++) {
            if (i < list.size() - 1 && list.get(i - 1).isEmpty() && list.get(i + 1).isEmpty()) {
                text = new ArrayList<>();           // reinitializing the text
                textByTitle.put(list.get(i), text); // adding an entry that correspond to a new title
            } else if (!list.get(i).isEmpty()) {
                text.add(list.get(i));              // adding the next line of text
            }
        }
    }
    

    main()

    public static void main(String[] args) {
        List<String> myText = List.of(
            "Title1",
            "",
            "line1",
            "line2",
            "",
            "Title2",
            "",
            "line1",
            "line2",
            "line3"
        );
        // populating the map
        processText(myText);
        // displaying the result
        textByTitle.forEach((title, text) -> System.out.println(title + " -> " + text));
    }
    

    Output:

    Title1 -> [line1, line2]
    Title2 -> [line1, line2, line3]
    

    Note:

    • Use LinkedHashMap to preserve the order of titles.
    • Avoid using collections of row type (without generic type variable specified).
    • Leverage abstractions, write your code against interfaces. Don't make your code dependent on concrete classes like HashMap, ArrayList, etc. See What does it mean to "program to an interface"?
    • Avoid meaningless names like hashmap. The name of the variable should convey what it is meant to store (See Self-documenting code).