HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

A way to handle integer input

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
inputwayintegerhandle

Problem

I'm working on simple code that is to read input where:

  • The first line is a number of cases to consider.



  • The next lines are integers separated by a space that will be tested lately.



Possible input:

2
3 4
4 5


Possible output (just some multiplication example):

12
20


Questions:

  • I would like to know if there are 'better' ways to handle this kind of input.



-
What could be done to make this code more universal? For example, there is a variable int lineLength=3 and I have to modify It for other similar input (where lineLength is bigger):

2
3 4 5
4 5 6


-
What validation should be implemented (if someone gives bad input, maybe it could be done in X ways (the handling))?

  • Do I break any good-programming rules? (I intended to write this only in class Main)



```
import java.io.IOException;
import java.util.Scanner;
import java.util.Arrays;

public class Main {

public static void main(String[] args) throws IOException {

/ Reading number of tests (NO VALIDATION) /
/ nextInt() doesnt read the last newline character of input /
Scanner read = new Scanner(System.in);
int numberOfTests = read.nextInt();

/ Consuming newline character/
read.nextLine();

String line[] = new String[numberOfTests];

/ Reading line excluding line separator at the end (NO VALIDATION) /
for (int i = 0; i < numberOfTests; i++)
line[i] = read.nextLine();

/ Printing array of String(lines) /
System.out.print(Arrays.toString(line));

/ Creating the array of ints (NO VALIDATION) /
int lineLength = 3;
int num[][] = new int[numberOfTests][lineLength];

/ Extracting integers from line /
for (int i = 0; i < numberOfTests; i++) {
int k = 0;
for (int j = 0; j < lineLength; j++) {
if (Character.isSpaceChar((line[i].charAt(j))) != true) {
num[i][k++] = Character.getNumericValue(line[i].charAt(j));
}
}
}

/ Printing array of integers to test /
int numToTests = 2;
for (int i = 0; i < numberO

Solution

Behaviour

I assume that you are writing this code in preparation for some programming challenges involving an online judge. In that case, it's unconventional that you are producing a matrix of digits. That is, each element is a single digit, no negative numbers, and no numbers larger than 9.

Usually, each line represents an independent test case. You should be able to compute a result for each line of input without waiting for all of the input to be read first.

Abstraction

If you want to focus on input-handling as a problem to be solved, then the "proper" solution would be to provide a convenient way for your computation code to fetch its input. The goal would be to enable simple code like:

public class Multiply {
    public static int product(int[] numbers) {
        int product = 1;
        for (int n : numbers) {
            product *= n;
        }
        return product;
    }

    public static void main(String[] args) {
        IntTestCaseInput input = new IntTestCaseInput(System.in);
        for (int[] multProblem : input) {
            System.out.println(product(multProblem));
        }
    }
}


Here is a class that could achieve that:

import java.io.*;
import java.util.*;

public class IntTestCaseInput implements Iterable {
    private class Iter implements Iterator {
        public int cases = -1;

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean hasNext() {
            try {
                maybeInitialize();
                return cases > 0;
            } catch (IOException e) {
                return false;
            }
        }

        @Override
        public int[] next() {
            try {
                maybeInitialize();
                if (cases == 0) {
                    throw new NoSuchElementException();
                }
                cases--;

                String[] strings = IntTestCaseInput.this.in.readLine().split("\\s+");
                int[] numbers = new int[strings.length];
                for (int i = 0; i  iterator() {
        return new Iter();
    }
}


In total, this results in a lot more code than your in your original question. However, once the calculations start getting more complicated, you may find that getting the input routines out of the way is worthwhile.

Code Snippets

public class Multiply {
    public static int product(int[] numbers) {
        int product = 1;
        for (int n : numbers) {
            product *= n;
        }
        return product;
    }

    public static void main(String[] args) {
        IntTestCaseInput input = new IntTestCaseInput(System.in);
        for (int[] multProblem : input) {
            System.out.println(product(multProblem));
        }
    }
}
import java.io.*;
import java.util.*;

public class IntTestCaseInput implements Iterable<int[]> {
    private class Iter implements Iterator<int[]> {
        public int cases = -1;

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean hasNext() {
            try {
                maybeInitialize();
                return cases > 0;
            } catch (IOException e) {
                return false;
            }
        }

        @Override
        public int[] next() {
            try {
                maybeInitialize();
                if (cases == 0) {
                    throw new NoSuchElementException();
                }
                cases--;

                String[] strings = IntTestCaseInput.this.in.readLine().split("\\s+");
                int[] numbers = new int[strings.length];
                for (int i = 0; i < strings.length; i++) {
                    numbers[i] = Integer.parseInt(strings[i]);
                }
                return numbers;
            } catch (IOException e) {
                throw new NoSuchElementException(e.getMessage());
            }
        }

        /**
         * On first use, find out how many test cases to expect.
         */
        private void maybeInitialize() throws IOException {
            if (cases < 0) {
                cases = Integer.parseInt(IntTestCaseInput.this.in.readLine());
            }
        }
    }

    private BufferedReader in;

    public IntTestCaseInput(InputStream in) {
        this(new InputStreamReader(in));
    }

    public IntTestCaseInput(Reader in) {
        this.in = (in instanceof BufferedReader) ?
            (BufferedReader)in : new BufferedReader(in);
    }

    @Override
    public Iterator<int[]> iterator() {
        return new Iter();
    }
}

Context

StackExchange Code Review Q#75855, answer score: 8

Revisions (0)

No revisions yet.