Repository: TheAlgorithms/Java
File: src/main/java/com/thealgorithms/strings/AhoCorasick.java (Java)

Code before:
             */
            ArrayList<ArrayList<Integer>> positionByStringIndexValue = new ArrayList<>(patterns.length); // Stores positions where patterns are found in the text
            Node parent = root; // Start searching from the root node

            for (int i = 0; i < patterns.length; i++) {
                positionByStringIndexValue.add(new ArrayList<Integer>()); // Initialize a list to store positions of the current pattern
            }

            for (int i = 0; i < text.length(); i++) {
                char ch = text.charAt(i); // Get the current character in the text

                // Check if the current node has a child for the current character
                if (parent.getChild().containsKey(ch)) {
                    parent = parent.getChild().get(ch); // Update the current node to the child node

                    // If the current node represents a pattern, record its position in positionByStringIndexValue
                    if (parent.getPatternInd() > -1) {
                        positionByStringIndexValue.get(parent.getPatternInd()).add(i);
                    }

                    Node outputLink = parent.getOutputLink();
                    // Follow output links to find and record positions of other patterns
                    while (outputLink != null) {
                        positionByStringIndexValue.get(outputLink.getPatternInd()).add(i);
                        outputLink = outputLink.getOutputLink();
                    }
                } else {
                    // If no child node exists for the character, backtrack using suffix links
                    while (parent != root && !parent.getChild().containsKey(ch)) {
                        parent = parent.getSuffixLink();
                    }
                    if (parent.getChild().containsKey(ch)) {
                        i--; // Decrement i to reprocess the same character
                    }
                }
            }
            setUpStartPoints(positionByStringIndexValue);
            return positionByStringIndexValue;
        }
        // by default positionByStringIndexValue contains end-points. This function converts those
        // endpoints to start points
        private void setUpStartPoints(ArrayList<ArrayList<Integer>> positionByStringIndexValue) {
            for (int i = 0; i < patterns.length; i++) {
                for (int j = 0; j < positionByStringIndexValue.get(i).size(); j++) {
                    int endpoint = positionByStringIndexValue.get(i).get(j);
                    positionByStringIndexValue.get(i).set(j, endpoint - patterns[i].length() + 1);
                }
            }
        }
    }


Review comment (suggestion):
This ask to be in a separate method. In order to make it _nice_ I would suggest to create another class like `RawSearchResult`. It could be either derived from `ArrayList<ArrayList<Integer>>` (I would call it a _tricky_ approach) or simply a class having one member of the type `ArrayList<ArrayList<Integer>>`.

This comment is not a _must_.

Code after:
        // Searches for patterns in the input text and records their positions
        public ArrayList<ArrayList<Integer>> searchIn(final String text) {
            var positionByStringIndexValue = initializePositionByStringIndexValue(); // Initialize a list to store positions of the current pattern
            Node parent = root; // Start searching from the root node

            PatternPositionRecorder positionRecorder = new PatternPositionRecorder(positionByStringIndexValue);

            for (int i = 0; i < text.length(); i++) {
                char ch = text.charAt(i); // Get the current character in the text

                // Check if the current node has a child for the current character
                if (parent.getChild().containsKey(ch)) {
                    parent = parent.getChild().get(ch); // Update the current node to the child node
                    positionRecorder.recordPatternPositions(parent, i); // Use the method in PatternPositionRecorder to record positions
                } else {
                    // If no child node exists for the character, backtrack using suffix links
                    while (parent != root && !parent.getChild().containsKey(ch)) {
                        parent = parent.getSuffixLink();
                    }
                    if (parent.getChild().containsKey(ch)) {
                        i--; // Decrement i to reprocess the same character
                    }
                }
            }

            setUpStartPoints(positionByStringIndexValue);
            return positionByStringIndexValue;
        }

        // by default positionByStringIndexValue contains end-points. This function converts those
        // endpoints to start points
        private void setUpStartPoints(ArrayList<ArrayList<Integer>> positionByStringIndexValue) {
            for (int i = 0; i < patterns.length; i++) {
                for (int j = 0; j < positionByStringIndexValue.get(i).size(); j++) {
                    int endpoint = positionByStringIndexValue.get(i).get(j);
                    positionByStringIndexValue.get(i).set(j, endpoint - patterns[i].length() + 1);
                }
            }
        }
    }

    // Class to handle pattern position recording
    private static class PatternPositionRecorder {
        private ArrayList<ArrayList<Integer>> positionByStringIndexValue;

        // Constructor to initialize the recorder with the position list
        PatternPositionRecorder(final ArrayList<ArrayList<Integer>> positionByStringIndexValue) {
            this.positionByStringIndexValue = positionByStringIndexValue;
        }

        /**