views:

5746

answers:

4

I'm used to python, so this is a bit confusing to me. I'm trying to take in input, line-by-line, until a user inputs a certain number. The numbers will be stored in an array to apply some statistical maths to them. Currently, I have a main class, the stats classes, and an "reading" class.

Two Questions:

  1. I can't seem to get the input loop to work out, what's the best practice for doing so.

  2. What is the object-type going to be for the reading method? A double[], or an ArrayList?

    1. How do I declare method-type to be an arraylist?

    2. How do I prevent the array from having more than 1000 values stored within it?

Let me show what I have so far:

public static java.util.ArrayList readRange(double end_signal){
    //read in the range and stop at end_signal

    ArrayList input = new ArrayList();
    Scanner kbd = new Scanner( System.in );
    int count = 0;
    do{
        input.add(kbd.nextDouble());
        System.out.println(input); //debugging
        ++count;
    } while(input(--count) != end_signal);
    return input;
}

Any help would be appreciated, pardon my newbieness...

+5  A: 

What you need in your loop condition is:

while ( input.get( input.size()-1 ) != end_signal );

What you're doing is decrementing the counter variable.

Also you should declare the ArrayList like so:

ArrayList<Double> list = new ArrayList<Double>();

This makes the list type-specific and allows the condition as given. Otherwise there's extra casting.

Jason Cohen
You should use the List interface instead of ArrayList.List<Double> list = new ArrayList<Double>();
Kamikaze Mercenary
Why? As long as it returns a List in the end it doesn't matter.
Jason Cohen
A: 

** public static java.util.ArrayList readRange(double end_signal){ //read in the range and stop at end_signal

ArrayList input = new ArrayList();
Scanner kbd = new Scanner( System.in );
int count = 0;
do{
    input.add(Double.valueOf(kbd.next()));
    System.out.println(input); //debugging
    ++count;
} while(input(--count) != end_signal);
return input;

}

**

l_39217_l
+2  A: 

Answers:

>1. I can't seem to get the input loop to work out, what's the best practice for doing so.

I would rather have a simple while loop instead of a do{}while... and place the condition in the while... In my example it read:

while the read number is not end signal and count is lower than limit: do.

>2. What is the object-type going to be for the reading method? A double[], or an ArrayList?

An ArrayList, however I would strongly recommend you to use List ( java.util.List ) interface instead. It is a good OO practice to program to the interface rather to the implementation.

>2.1How do I declare method-type to be an arraylist?

See code below.

>2.2. How do I prevent the array from having more than 1000 values stored within it?

By adding this restriction in the while condition.

import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;

public class InputTest{

    private int INPUT_LIMIT = 10000;

    public static void main( String [] args ) {
        InputTest test = new InputTest();
        System.out.println("Start typing numbers...");
        List list = test.readRange( 2.0 );
        System.out.println("The input was " +  list );
    }

    /**
     * Read from the standar input until endSignal number is typed.
     * Also limits the amount of entered numbers to 10000;
     * @return a list with the numbers.
     */
    public List readRange( double endSignal ) {
        List<Double> input = new ArrayList<Double>();
        Scanner kdb = new Scanner( System.in );
        int count = 0;
        double number = 0;
        while( ( number = kdb.nextDouble() ) != endSignal && count < INPUT_LIMIT ){
            System.out.println( number );
            input.add( number );
        }
        return input;
    }
}

Final remarks:

It is preferred to have "instance methods" than class methods. This way if needed the "readRange" could be handled by a subclass without having to change the signature, thus In the sample I've removed the "static" keyword an create an instance of "InputTest" class

In java code style the variable names should go in cammel case like in "endSignal" rather than "end_signal"

OscarRyz
A: 

Hi, I think you started out not bad, but here is my suggestion. I'll highlight the important differences and points below the code:

package console;

import java.util.; import java.util.regex.;

public class ArrayListInput {

public ArrayListInput() {
 // as list
 List<Double> readRange = readRange(1.5);

 System.out.println(readRange);
 // converted to an array
 Double[] asArray = readRange.toArray(new Double[] {});
 System.out.println(Arrays.toString(asArray));
}

public static List<Double> readRange(double endWith) {
 String endSignal = String.valueOf(endWith);
 List<Double> result = new ArrayList<Double>();
 Scanner input = new Scanner(System.in);
 String next;
 while (!(next = input.next().trim()).equals(endSignal)) {
  if (isDouble(next)) {
   Double doubleValue = Double.valueOf(next);
   result.add(doubleValue);
   System.out.println("> Input valid: " + doubleValue);
  } else {
   System.err.println("> Input invalid! Try again");
  }
 }
 // result.add(endWith); // uncomment, if last input should be in the result
 return result;
}

public static boolean isDouble(String in) {
 return Pattern.matches(fpRegex, in);
}

public static void main(String[] args) {
 new ArrayListInput();
}

private static final String Digits = "(\\p{Digit}+)";
private static final String HexDigits = "(\\p{XDigit}+)";
// an exponent is 'e' or 'E' followed by an optionally
// signed decimal integer.
private static final String Exp = "[eE][+-]?" + Digits;
private static final String fpRegex = ("[\\x00-\\x20]*" + // Optional leading "whitespace"
  "[+-]?(" + // Optional sign character
  "NaN|" + // "NaN" string
  "Infinity|" + // "Infinity" string

  // A decimal floating-point string representing a finite positive
  // number without a leading sign has at most five basic pieces:
  // Digits . Digits ExponentPart FloatTypeSuffix
  // 
  // Since this method allows integer-only strings as input
  // in addition to strings of floating-point literals, the
  // two sub-patterns below are simplifications of the grammar
  // productions from the Java Language Specification, 2nd
  // edition, section 3.10.2.

  // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
  "(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" +

  // . Digits ExponentPart_opt FloatTypeSuffix_opt
  "(\\.(" + Digits + ")(" + Exp + ")?)|" +

  // Hexadecimal strings
  "((" +
  // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
  "(0[xX]" + HexDigits + "(\\.)?)|" +

  // 0[xX] HexDigits_opt . HexDigits BinaryExponent
  // FloatTypeSuffix_opt
  "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +

  ")[pP][+-]?" + Digits + "))" + "[fFdD]?))" + "[\\x00-\\x20]*");// Optional
                  // trailing
                  // "whitespace"

}

  1. In Java it's a good thing to use generics. This way you give the compiler and virtual machine a hint about the types you are about to use. In this case its double and by declaring the resulting List to contain double values, you are able to use the values without casting/type conversion:

    if (!readRange.isEmpty()) {
     double last = readRange.get(readRange.size() - 1);
    }
    
  2. It's better to return Interfaces when working with Java collections, as there are many implementations of specific lists (LinkedList, SynchronizedLists, ...). So if you need another type of List later on, you can easy change the concrete implementation inside the method and you don't need to change any further code.

  3. You may wonder why the while control statement works, but as you see, there are brackets around next = input.next().trim(). This way the variable assignment takes place right before the conditional testing. Also a trim takes playe to avoid whitespacing issues

  4. I'm not using nextDouble() here because whenever a user would input something that's not a double, well, you will get an exception. By using String I'm able to parse whatever input a user gives but also to test against the end signal.

  5. To be sure, a user really inputed a double, I used a regular expression from the JavaDoc of the Double.valueOf() method. If this expression matches, the value is converted, if not an error message will be printed.

  6. You used a counter for reasons I don't see in your code. If you want to know how many values have been inputed successfully, just call readRange.size().

  7. If you want to work on with an array, the second part of the constructor shows out how to convert it.

  8. I hope you're not confused by me mixin up double and Double, but thanks to Java 1.5 feature Auto-Boxing this is no problem. And as Scanner.next() will never return null (afaik), this should't be a problem at all.

  9. If you want to limit the size of the Array, use

Okay, I hope you're finding my solution and explanations usefull, use result.size() as indicator and the keyword break to leave the while control statement.

Greetz, GHad

GHad