Search code examples
javarun-length-encoding

Run-length encoding in java


How to print out the number of a specific digit along with the digit itself in form "nxw." n is the frequency of the number, w is the number itself.

So, for example, if the user's input was 1 1 1. The output would be 3x1.

If the user's input was 1 1 1 at the first line and 7 7 1 1 0 at the second line. The output would be 3x1.2x7.2x1.1x0. with no spaces.

Note:

  • loop ends with a dot.

  • numbers don't have to be in a specific order

  • user can input as many digits as they want.

So for example, Input can be 1 1 1 at the first line 7 7 1 1 0 at the second ... etc.

This is my code so far. But I know that it's not true.

import java.util.*;

public class LaufLaengenKodierung {

public static void main(String[] args) {
        
    Scanner sc = new Scanner(System.in);
        
    int freq = 0;
    int oldNum = 0;
    int num = 0;
    boolean first = true;
        
    while(sc.hasNextInt()) {
            
        int i = sc.nextInt();
            
        if(i == oldNum) {
                
            freq++;
            num = i;
                
        } else if(i != oldNum) {
                
            freq = 1;
            oldNum = i;
            num = i;
                
            if(first) {
                    
                first = false;
                num = i;
                freq = 1;
                    
            }
        }
    }
        
    System.out.print(freq + "x" + num + ".");
    sc.close();
}
        
}

Solution

  • Existing code needs to be slightly refactored to print the frequency and integer value as soon as a sub-sequence of the same values ends.

    static void printRLE(String input) {
        Scanner sc = new Scanner(input);
        int freq = 0;
        int oldNum = 0;
        boolean first = true;
            
        while(sc.hasNextInt()) {
                
            int i = sc.nextInt();
            
            if (i != oldNum || first) {
                if (first)
                    first = false;
                else // integer value changed
                    System.out.printf("%dx%d.", freq, oldNum);
                oldNum = i;
                freq = 1;
            } else {
                freq++;
            }
        }
        if (!first)    
            System.out.printf("%dx%d.%n", freq, oldNum);
        else 
            System.out.println("No integer found"); // or print 0x0 if it's correct
        sc.close();    
    }
    

    Tests:

    String[] tests = {
        "",
        "abc.",
        "11 11 11",
        "1 1 1\n7 7 1 1 0",
        "0 0 0",
    };    
    
    for (String test: tests) {
        System.out.println("test=[" + test + "]");
        printRLE(test);
        System.out.println("--------");
    }
    

    Output:

    test=[]
    No integer found
    --------
    test=[abc.]
    No integer found
    --------
    test=[11 11 11]
    3x11.
    --------
    test=[1 1 1
    7 7 1 1 0]
    3x1.2x7.2x1.1x0.
    --------
    test=[0 0 0]
    3x0.
    --------
    

    Update If separate digits need to be counted only (not the integer numbers), e.g. input 11 11 11 should be converted to 6x1. instead of 3x11. as shown above, the method should be refactored to process the digits inside numbers:

    static void printRLEDigits(String input) {
        Scanner sc = new Scanner(input);
        int freq = 0;
        int oldNum = 0;
        boolean first = true;
            
        out: while(sc.hasNext()) {
                
            String s = sc.next(); // getting "number" delimited with whitespaces
            for (char c: s.toCharArray()) {
                if (!Character.isDigit(c)) {
                    break out;
                }
                int i = c - '0';
                if (i != oldNum || first) {
                    if (first)
                        first = false;
                    else // digit changed
                        System.out.printf("%dx%d.", freq, oldNum);
                    oldNum = i;
                    freq = 1;
                } else {
                    freq++;
                }
            }
        }
        if (!first)    
            System.out.printf("%dx%d.%n", freq, oldNum);
        else 
            System.out.println("No integer found");
        sc.close();    
    }
    

    Output for tests: "11 11 11", "112 223", "1 1 1\n7 7 1 1 0", "0 0 0":

    test=[11 11 11]
    6x1.
    --------
    test=[112 223]
    2x1.3x2.1x3.
    --------
    test=[1 1 1
    7 7 1 1 0]
    3x1.2x7.2x1.1x0.
    --------
    test=[0 0 0]
    3x0.
    --------
    

    Online demo of both methods printRLE and printRLEDigits