Java Scanner not working as expected - java

I am trying to read a file into my java program where the first row in the txt file is an int and everything after is a long. The issue that I am having is every single line of code in the while loop is calling s.nextint() and s.nextLong() (at least when I put a watch on them in Eclipse). I want them only to increment through the text file where I call them.
Firstly, what am I doing wrong because it was my understanding they should only increment when called and not on every line of code, and is there a better way to do this? I was thinking if need be I could just load them all in as a single type to an array and cast later, but this wouldn't be what I consider reasonable. I feel this should be fairly simple but I am overlooking something.
Also lets say there are 10 numbers in the text file and go 1-10. I understand that it is a waste to save a small number as an int but just go with it.
public static long[] readfile()
{
int row = 1;
Scanner s = null;
long[] nums = null;
try {
s = new Scanner(new BufferedReader( new FileReader("text.txt")));
while (s.hasNext()) {
if(row == 1){
nums = new long[s.nextInt()];
row++;
}
else {
nums[row - 2] = s.nextLong();
row++;
}
}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
finally {
if (s != null) {
s.close();
}
}
return nums;
}

I'd prefer something like this:
do
{
if(row == 1){
nums = new long[s.nextInt()];
row++;
}
else
{
nums[row] = s.nextLong();
row++;
}
}while(s.hasNextLong());
I didn't try to compile or debug it; holler if you need further help. (It assumes there will be an integer atop the file, as you said would be the case. You should probably add code to guard against that not happening.)

You're code is throwing an ArrayIndexOutOfBoundsException. You're trying to use row for two purposes which throws off your array indexing. By the time we get to the else block, row is equal to 2 and you're trying to apply row to an array from 0 - 9 (10 longs for example).
You should trying initializing your array after checking hasNextInt() then get your long numbers after checking hasNextLong()
Code Sample (text.txt has 10 numbers [1234567890]):
public static void main(String[] args) throws Exception {
long[] longs = readfile();
if (longs != null) {
for (long l : longs) {
System.out.println(l);
}
}
}
public static long[] readfile() {
int row = 0;
Scanner s = null;
long[] nums = null;
try {
s = new Scanner(new BufferedReader(new FileReader("text.txt")));
if (s.hasNextInt()) {
nums = new long[s.nextInt()];
}
while (s.hasNextLong()) {
nums[row] = s.nextLong();
row++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (s != null) {
s.close();
}
}
return nums;
}
Results:
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890

I've generally found that Scanners behave oddly when attempting to read multiple types. I'd create a separate Scanner for each type that you'll be reading.

It seems that the issue i stated was having something to do with an eclipse error. If i just run the code or set a breakpoint after the readfile in the main my code works as expected, but when I stepped through values weren't being assigned right by eclipse i'm guessing. Interesting issue. I would like to see exactly what was causing it. Seems very unlikely but isn't that coding? nothing goes as expected.

Related

File Reading in java to obtain a single line by providing line number

I have a java file reader method. The file consist of many line ( upt 100 lines). I was interested to read and store Line 2 and as well as line 5 - 15 while am storing them into an arrayList.
The issue am having is, I dunno how to get the content of a specific line
For example : this is the file content.
Time after time
Heart to heart
Boys will be boys
Hand in hand
Get ready; get set; go
Hour to hour
Sorry, not sorry
Over and over
Home sweet home
Smile, smile, smile at your mind as often as possible.
Alone, alone at last
Now you see me; now you don’t
Rain, rain go away
All for one and one for all
It is what it is
Java API that am using is
File f = new File ("t.txt");
and
BufferedReader br = new BufferedReader(new FileReader(f))
Files are read through streams and each line is accessed sequentially, not randomly. One way to handle this is to have a counter that you check inside a loop, something like:
int count = 1; // line counter
String line; // current line being read
while((line = br.readLine()) != null) {
if(count == 2 ||
(count >= 5 && count <= 15))
arrayList.add(line);
count++;
}
Java 7 introduced NIO.21 which includes class java.nio.Files which declares method readAllLines2. Since you state that your file may contain a maximum of 100 lines, method readAllLines seems appropriate. Then all you need to do is indicate the index[es] of the line[s] you want. The below code demonstrates.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class FileLine {
public static void showLines(List<String> lines, int first, int last) {
if (lines != null && first >= 0 && last < lines.size() && first <= last) {
for (int i = first; i <= last; i++) {
System.out.println(lines.get(i));
}
}
}
public static void main(String[] args) {
Path path = Paths.get("t.txt");
try {
List<String> lines = Files.readAllLines(path); // throws java.io.IOException
showLines(lines, 2, 2);
System.out.println("================================================================");
showLines(lines, 5, 14);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
Note that the index of the first line in the List is 0 (zero).
The output when I run the above code is:
Boys will be boys
================================================================
Hour to hour
Sorry, not sorry
Over and over
Home sweet home
Smile, smile, smile at your mind as often as possible.
Alone, alone at last
Now you see me; now you don’t
Rain, rain go away
All for one and one for all
It is what it is
Alternatively, if you want to collect certain file lines into a separate list, then consider the following code (which is slightly changed from the above code).
public class FileLine {
public static List<String> getLines(List<String> lines, int first, int last) {
List<String> list = new ArrayList<>();
if (lines != null && first >= 0 && last < lines.size() && first <= last) {
for (int i = first; i <= last; i++) {
list.add(lines.get(i));
}
}
return list;
}
public static void main(String[] args) {
Path path = Paths.get("t.txt");
try {
List<String> lines = Files.readAllLines(path);
List<String> selectedLines = getLines(lines, 2, 2);
selectedLines.addAll(getLines(lines, 5, 14));
System.out.println(selectedLines);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
Running the alternative code gives the following output:
[Boys will be boys, Hour to hour, Sorry, not sorry, Over and over, Home sweet home, Smile, smile, smile at your mind as often as possible., Alone, alone at last, Now you see me; now you don’t, Rain, rain go away, All for one and one for all, It is what it is]
1 NIO was introduced in Java 1.4
2 To be precise, that method was added in Java 8. In Java 7 you also had to indicate the charset of the file.
Extract the logic you need into a method looking at the general case.
Given a file f, read only a subset of lines. One way of looking at this is with a method like
List<String> readLines(File f, Function<Integer, Boolean> check);
You could define such a method as follows:
List<String> readLines(File f, Function<Integer, Boolean> check) throws IOException {
List<String> list = new ArrayList<>();
int count = 0;
String line;
try (BufferedReader br = new BufferedReader(new FileReader(f))) {
while((line = br.readLine()) != null) {
count++;
if (check.apply(count)) {
list.add(line);
}
}
}
return list;
}
Defining the check function as appropriate whereby given an integer it will return true / false if the line is to be added, you can generalize for different use cases.
For exmaple (in your case), the check function would be
Function<Integer, Boolean> check = lineNumber -> lineNumber == 2 || (lineNumber >= 5 && lineNumber <= 15);
get line(s) by their respective line-number with lambda
Set<Integer> linesToGet = Set.of(2, 5, 15);
try(Stream<String> stream = Files.lines(Paths.get("test.txt"))) {
int[] line = {1};
List<String> list = stream.filter(s -> linesToGet.contains(line[0]++))
.collect(toList());
}
catch (IOException ex) {…}
gets: [Heart to heart, Get ready; get set; go, It is what it is]

How to make this code become more effcient?

So I have been doing competitive programming using java, my code is ACCEPTED in codeforces. But I still think this code doesn't look so good, cause it needs 2 "for loops" to identify the duplication. if it is only one "for loops", it still has duplication in the strings.
This is the problem: https://codeforces.com/problemset/problem/236/A.
So basically, the code will try to find the distinct characters in the strings, then if the length of the string is odd, it will print "IGNORE HIM", else "CHAT WITH HER!".
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
String a;
int counter=0;
Scanner sc= new Scanner(System.in);
a=sc.next();
StringBuilder b= new StringBuilder(a);
int count = 0;
for(int i=0;i<b.length();i++)
{
for(int j=i+1;j<b.length();j++) {
if(b.charAt(i)==b.charAt(j)) {
b=b.deleteCharAt(j);
}
}
}
for(int i=0;i<b.length();i++)
{
for(int j=i+1;j<b.length();j++) {
if(b.charAt(i)==b.charAt(j)) {
b=b.deleteCharAt(j);
}
}
}
counter=b.length();
if(counter%2==0)
{
System.out.println("CHAT WITH HER!");
}
else
{
System.out.println("IGNORE HIM!");
}
}
}
You can replace most of this code by this one line:
int count = a.chars().distinct().count();
This transforms you string input into a stream of characters, gets the distinct values and returns the count.
Using streams is a good option. If you want to go plain old route, then you can use a hashset. Basically if character is in hashset, then move to next char, else add to hashset and increase counter by 1.
Building upon and completing #Guillaume's answer
String a = "xiaodao";
String out = a.chars().distinct().count() % 2 == 0 ? "CHAT WITH HER!" : "IGNORE HIM!";
System.out.println(out);
I would use a Hashset because it will contain a distinct set of all characters you add. You can just go through the list once and use size() to get the unique character count.
...
Set<Character> characters = new HashSet<>()
for(int i=0;i<b.length();i++)
{
characters.add(b.charAt(i));
}
if(characters.size()%2==0) {
...

Parsed My Text File - Now How Can I Take the Max-Min Value From Each Row and Assign Them as Doubles?

I am trying to parse a text file that contains data similar to below:
%abc
-12 -9 10 150 180
-4.31 -2.29 -0.3689 .0048 4.987 6.123 19
%xyz
Other data, not important to what I am doing
I have written this code to parse the top two lines, as well as the other data, except for the placeholder value %abc:
public static void main(String[] args) {
Scanner scan;
File file = new File("kx=2.2_Au.txt");
try {
BufferedReader in = new BufferedReader(new FileReader("kx=2.2_Au.txt"));
String str;
str = in.readLine();
while ((str = in.readLine()) != null) {
System.out.println(str);
}
in.close();
}
catch (IOException e) {
System.out.println("File Read Error");
}
}
From this point, I need to take the max-min for each of the top two lines, and assign their value to a string variable. I am not sure how to go about this part.
Edit:
My code now looks like the following:
public void execute() {
File file = new File("upload:///file1");
try {
BufferedReader in = new BufferedReader(new FileReader(file));
String str;
str = in.readLine();
while ((str = in.readLine()) != null) {
String[] parts = str.split(" ");
for (String item : parts) {
double min;
double max;
min = (Double.isNaN(min) || min > Double.parseDouble(item) ?
Double.parseDouble(item) : min);
max = (Double.isNaN(max) || max<Double.parseDouble(item) ?
Double.parseDouble(item) : max);
}
//System.out.println(str);
}
in.close();
} catch (IOException e) {
System.out.println("File Read Error");
}
}
At this point I'm getting the error that the variables min and max may not have been initialized although they are defined as doubles right before they're used in the code - any more input would be sincerely appreciated. Thanks.
As has been mentioned, you need to initialize your variables, rather than just declaring them. I would highly suggest, from the nature of the comment regarding initializing the variable before the value it will be assigned, that you look at some of the code tutorials that can be found free on the internet. This will give you a better understanding of the basics of the Java language.
With that being said, the compiler is directly telling you that there is an issue, and is telling you exactly what it is. Initialize your doubles, and recompile; the errors will indeed go away. If you try to compile prior to making these changes, it is likely you are seeing something similar to this:
Somefile.java:123:error: variable min might not have been initialized
min = (Double.isNan(min) || ...
Changing this declaration
double min;
double max;
to instead both declare and initialize the variables
double min = 0.00;
double max = 0.00;
will resolve the specific compiler error you mentioned.
With that being said, there are some other issues that you will face with the implementation that you have. If you know that after a certain point, token, or other symbol within your input file you will not care about any other data, it is suggestible to restrict the lines being read to only those necessary to perform the work.
I would also suggest rewriting the assignment of values to min and max, as they are not going to detect non-Double data, which looks like what is intended by calling Double.isNan(). This article might be a good approach.

Why did I get an "ArrayIndexOutOfBoundsException"?

I'm pretty new to programming and working on an assignment for class. Now, I'm not asking for anyone to write my code for me but I'm stuck with a runtime error. In the assignment we need to read a file, use the first line, "15", to initialize the size of an array, and proceed to fill the array with the information from each line.
edit: I didn't want to post all of the code because I thought it would look too long but because of the downvotes for being vague, here it goes.
File:
15
produce,3554,broccoli,5.99,1
produce,3554,broccoli,5.99,1
produce,3555,carrots,2.23,0.25
produce,3555,carrots,2.23,0.25
produce,3555,carrots,2.23,0.25
cleaning,2345,windex,5.99,1 unit
cleaning,2345,windex,5.99,1 unit
cleaning,2345,windex,5.99,1 unit
cleaning,2345,windex,5.99,1 unit
cleaning,2346,toilet paper,12.99,4 rolls
cleaning,2346,toilet paper,12.99,4 rolls
cleaning,2335,windex,2.25,1 mini sprayer
cleaning,1342,wipes,3.99,10 units
cleaning,1342,wipes,3.99,10 units
produce,3546,lettuce,2.99,0.5
My Error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 15
at Inventory.readFile(Inventory.java:45)
at Inventory.<init>(Inventory.java:12)
at Supermarket.main(Supermarket.java:3)
Class with the Line 45 in Question (line 45 is commented, scroll to the right)"
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class Inventory{
Product[] list;
String[] invData;
private int i = 0;
public int count;
public Inventory (String f){
readFile(f);
}
public int indexOfProduct(int code){
for(i=0; i<list.length; i++){
if (list[i] != null)
if (list[i].getCode() == code)
return i;
}
return -1;
}
public Product delete(int pos){
Product temp = new Product();
temp = list[pos];
list[pos] = null;
return temp;
}
public void readFile(String fileName){
try{
File invList = new File (fileName);
Scanner s = new Scanner(invList);
int itemCount = s.nextInt();
list = new Product[itemCount];
count = itemCount;
while (s.hasNext()){
String line = s.nextLine();
invData = line.split(",");
if (invData[0].equals("produce")){
list[i] = new Produce(invData[1], invData[2], invData[3], invData[4]); // This is Line 45, Where the error occurs
} else if(invData[0].equals("cleaning")){
list[i] = new Cleaning(invData[1], invData[2], invData[3], invData[4]);
}
i++;
}//end of while loop
} catch (FileNotFoundException Abra) {
String error = Abra.getMessage();
System.out.println(error);
}
} // end of method
public Product findCode(int c){
for(int i=0; i<list.length;i++)
if(list[1].getCode() == c)
return list[i];
return null;
}//end of method
}//end of class
Why did I get an "ArrayIndexOutOfBoundsException"? I hope someone can point out the flaw in my logic so I don't repeat it again.
Your issue is clearly with the use of i, as that is the only variable index on that line, and the out of range index is "15", which is just past the end of your 15-item array. So, couple of issues, all surrounding the use of i:
As nhellwig mentioned, be sure that i is actually initialized to 0 before calling this function.
Additionally, you're putting a lot of faith in the consistency of the item number in the file and the actual number of items. You should either produce a warning and stop trying to store items in the array if i >= itemCount, or use a container like an ArrayList that can grow to accommodate new items instead of a fixed size array.
Edit: Also, I should point out that you increment i whether you read an item or not, which means even blank lines will increment i, causing gaps in your list or array overruns. Since itemCount is the number if items, you should stick to that and only increment i if you read an actual item.
In that same spirit, you should verify that invData.length == 5 after you call split(), because a misplaced comma, etc. in your file may also end up with an OOB error. Granted, for your project, it's probably OK to make assumptions about the number of elements in a line that starts with "produce" or "cleaning", but in general it's important to be cautious with data coming from a user-created file.
I found the answer to be that I needed an "s.nextLine();"
Because I used "s.nextInt();" the pointer was just hangin around at the end of "15" in my file. Then, when the first line in the While loop "String line = s.nextLine();" executed the pointer moved from the end of 15 to before the p in produce in the 2nd line of the list file.
The working method looks like this:
public void readFile(String fileName){
try{
File invList = new File (fileName);
Scanner s = new Scanner(invList);
int itemCount = s.nextInt();
s.nextLine(); // This is the new line that made it work
list = new Product[itemCount];
count = itemCount;
while (s.hasNext()){
String line = s.nextLine(); //moves file pointer over one
invData = line.split(",");
if (invData[0].equals("produce")){
list[i] = new Produce(invData[1], invData[2], invData[3], invData[4]);
} else if(invData[0].equals("cleaning")){
list[i] = new Cleaning(invData[1], invData[2], invData[3], invData[4]);
}
i++;
}//end of while loop
} catch (FileNotFoundException Abra) {
String error = Abra.getMessage();
System.out.println(error);
}
} // end of method
How many times do you call readFile? You should have i = 0; at the beginning of the function.
"i" should not be a global value but should be a method local variable, initialized to zero.

java- Read data from a file for further processing

I'm new to java and I would like to ask you for help. I have some data stored in a txt file, each line holds three integers, separated by space. I would like to read the data from the file and then put this data in arrays for further processing, if certain conditions are met (in my case- third int is greater than 50). I read some questions about how to read the number of lines in a file or the file itself, but I can't seem to combine it all together to make it work. The latest version of the code looks like this:
public class readfile {
private Scanner x;
public void openFile(){
try{
x = new Scanner(new File("file.txt"));
}
catch (Exception e){
System.out.println("could not find file");
}
}
public void readFile() throws IOException{
LineNumberReader lnr = new LineNumberReader(new FileReader(new File("file.txt")));
int i = lnr.getLineNumber();
int[] table1 = new int[i];
int[] table2 = new int[i];
while(x.hasNextInt()){
int a = x.nextInt();
int b = x.nextInt();
int c = x.nextInt();
for (int j=0; j< table1.length; j++)
{
if(c > 50)
{
table1[j]=a;
table2[j]=b;
}
}
}System.out.printf(" %d %d", table1, table2);
}
public void closeFile(){
x.close();
}
}
main is located in another file.
public static void main(String[] args) {
readfile r = new readfile();
r.openFile();
try {
r.readFile();
}
catch (Exception IOException) {} //had to use this block or it wouldn't compile
r.closeFile();
}
when I use %d on printf method i don't see anything, when I use %s I get some gibberish on the output like
[I#1c3cb1e1 [I#54c23942
what should I do to make it work (ie. print pairs of a b when c is > 50)?
Thanks in advance for any help, and sorry if this turns out to be some blatantly obvious problem, but I really ran out of ideas on how to improve this :)
You cannot print an entire array using %d. Loop through the array and print each value separately.
You are getting gibberish output because you are printing the Array References in printf()
For individual values use a loop like..
for(int i:table1){
System.out.print(""+i)
}
OR
To print in pairs substitute the following code...
if(c > 50)
{
table1[j]=a;
table2[j]=b;
System.out.printf("%d %d",a,b);
}
You cannot format your arrays as an int using printf. If you want to print the entire contents of your arrays, then use the helper function Arrays.toString(array).
E.g.
System.out.println(Arrays.toString(table1));
If I get you correct you have a file like
12 33 54
93 223 96
74 743 4837
234 324 12
and if the third integer is greater than 50 you want to store the first two?
List<String> input = FileUtils.readLines(new File("file.txt"), Charset.forName( "UTF-8" ));
HashMap<Integer, Integer> filtered = new HashMap<Integer, Integer>();
for (String current : input) {
String[] split = current.split(" ");
if (Integer.parseInt(split[2]) > 50)
filtered.put(Integer.parseInt(split[0]), Integer.parseInt(split[1]))
}
System.out.println(filtered);

Categories