Log Level Counter

easy Files and I/O

Problem

Each input line is a log entry: a level (DEBUG, ERROR, INFO or WARN, in capital letters) followed by a message. Print how many entries each level has, one line per level that appears, in alphabetical order: LEVEL count. If some lines start with another word, print a last line INVALID count.

Constraints

  • 1 <= lines <= 10^5

Examples

Input

INFO started
ERROR disk full
INFO running

Output

ERROR 1
INFO 2

Solutions

Best approachTime O(n log k)Space O(k)

Reading input line by line and splitting off the first word is the base of every log tool. A sorted map or a sorted key list gives a stable output order.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process lines.
 * Input   : Several lines.
 * Output  : Counts per level.
 * Approach: Parse the first word.
 * Time    : O(n log k)
 * Space   : O(k)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        // Step 1: A TreeMap keeps its keys in alphabetical order. We count the valid levels in it.
        java.util.Map<String, Integer> counts = new java.util.TreeMap<>();
        java.util.Set<String> levels = new java.util.HashSet<>(java.util.Arrays.asList("DEBUG", "ERROR", "INFO", "WARN"));
        int invalid = 0;

        for (String line : lines) {
            // Step 2: The level is the first word of the line.
            String level = line.split(" ")[0];
            if (levels.contains(level)) {
                counts.merge(level, 1, Integer::sum);
            } else {
                invalid++;
            }
        }

        // Step 3: Make one output line for each counted level, then the INVALID line if needed.
        java.util.List<String> output = new java.util.ArrayList<>();
        for (java.util.Map.Entry<String, Integer> entry : counts.entrySet()) {
            output.add(entry.getKey() + " " + entry.getValue());
        }
        if (invalid > 0) {
            output.add("INVALID " + invalid);
        }
        return output.toArray(new String[0]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (1)
  1. Which part of each line decides the level?