I have a text file with few numbers in a line ;
10 20 30 40 50
My motto is to read 3 numbers at a time and perform some operation on it.
Please help me to learn best ways to do this job.
I need to work on numbers in this fashion,
10 20 30
20 30 40
30 40 50 .....
If my text file has a line with 100000 numbers is it suggestable to load the entire file in memory and keep traversing and performing operations or is it good to copy the entire line in an array and perform operations on it?
Here is a simple way to do it:
int a, b, c;
// try with resources, scanner will be closed when we are done.
try (Scanner scan = new Scanner(new File("input.txt"))) {
// get the first three ints.
a = scan.nextInt();
b = scan.nextInt();
c = scan.nextInt();
doSomething(a, b, c);
// while there are more
while (scan.hasNext()) {
a = b;
b = c;
c = scan.nextInt();
doSomething(a, b, c);
}
} catch (FileNotFoundException | NoSuchElementException e) {
e.printStackTrace();
}
This will read one number at a time, and perform some operation in between each read.
If you want to read all the numbers before performing operation, you can use an array list.
ArrayList<Integer> list = new ArrayList<>();
// try with, scanner will be closed when we are done.
try (Scanner scan = new Scanner(new File("input.txt"))) {
// while there are more
while (scan.hasNext()) {
list.add(scan.nextInt());
}
} catch (FileNotFoundException | NoSuchElementException e) {
e.printStackTrace();
}
Then you can iterate through them.
for (int i : list) {
}
Using an IntBuffer instead of ArrayList would work if you know how many numbers there were.
For only 100000 values it probably doesn't make much difference if you load them as you need them or load them all first. If your operation takes a long time it might be better to load them all.
Well, it depends on what you want. Load all the numbers to the memory will take more time, but operations with the numbers in memory will be faster. If you don't want to allocate a "big" portion of your memory to hold all the numbers you can read the file and at the same time do the operation. Although, it will not make much difference, since the file just hold numbers and its size won't be to big.
Below is a code sample that achieves what you want.
Full Code
public static void main (String args[]){
//Scanner will read your file
Scanner scanner = null;
try {
scanner = new Scanner(new File("file.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// tmpInts will old the tmp values that are read
int [] tmpInts = new int[3];
// Holds a controller to know if we can do the operation
int i = 0;
while(scanner.hasNextInt()){
// Do the operation only when tmpInts has 3 numbers inside it
if(i > 2){
System.out.println("Read: ["+tmpInts[0] +" "+ tmpInts[1] +" "+ tmpInts[2]+"] Sum: "+(tmpInts[0] + tmpInts[1] + tmpInts[2]));
shiftInts(tmpInts);
tmpInts[2] = scanner.nextInt(); // Read next number
} else {
tmpInts[i] = scanner.nextInt(); // Read next number
i++;
}
}
// Check if there are at least 3 numbers in the file
// If not, don't do the operation
// If yes, this is the last operation call to handle the last state of tmpInts array
if(!isEmpty(tmpInts))
System.out.println("Read: ["+tmpInts[0] +" "+ tmpInts[1] +" "+ tmpInts[2]+"] Sum: "+(tmpInts[0] + tmpInts[1] + tmpInts[2]));
scanner.close(); // IMPORTANT! Don't forget to close your scanner
}
// Shift numbers one index left to put a third one in the last index of the array after
public static void shiftInts(int[] tmpInts) {
tmpInts[0] = tmpInts[1];
tmpInts[1] = tmpInts[2];
}
// Check if array is full. If it is not it means that your file doesn't have at least 3 numbers. i choosed 0 as default value in array, you can choose another one that won't appear in your file
public static boolean isEmpty(int[] tmpInts) {
for(int i: tmpInts){
if(i == 0){
return true;
}
}
return false;
}
Hope it helped!
I took line as a String and converted into array of integers to load all numbers into the memory. We can do required operations on integer array by iteration.
Below is the sample code :
public static void main(String[] args) {
String fileName = "temp1.txt";
String line;
try {
FileReader fileReader = new FileReader(fileName);
BufferedReader bufferedReader = new BufferedReader(fileReader);
while ((line = bufferedReader.readLine()) != null) {
String[] inputNumbers = line.split(",");
int numbers[] = new int[inputNumbers.length];
for (int i = 0; i < inputNumbers.length; i++) {
numbers[i] = Integer.parseInt(inputNumbers[i]);
}
for (int j = 0; j < numbers.length - 2; j++) {
int sum = numbers[j] + numbers[j + 1] + numbers[j + 2];
System.out.println(sum);
}
}
bufferedReader.close();
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Related
I'm working on a problem that requires me to store a very large amount of integers into an integer array. The input is formatted so that one line displays the amount of integers and the next displays all of the values meant to be stored. Ex:
3
12 45 67
In the problem there is closer to 100,000 integers to be stored. Currently I am using this method of storing the integers:
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] iVau = new int[n];
String[] temp = scanner.nextLine().split(" ");
for(int i = 0; i < n; i++) {
iVau[i] = Integer.parseInt(temp[i]);
}
This works fine, however the problem I am solving has a strict time limit and my current solution is exceeding it. I know that there is a more efficient way to store this input using buffered readers and input streams, but I don't know how to do it, can someone please show me.
The way you are using Scanner makes your program save a String containing the whole numbers at once, in memory. With 100000 numbers in the 2nd line of your input, it is not so efficient, you could read numbers one after the other without keeping the previous one in memory. So, this way, avoiding using Scanner.readLine() should make your program run faster. You will not have to read the whole line one time, and read a 2nd time this String to parse the integers from it: you will do both of these operations only once.
Here is an example. The method testing() does not use any Scanner. The method testing2() is the one you provided. The file tst.txt contains 100000 numbers. The output from this program, on my Mac Mini (Intel Core i5#2.6GHz) is:
duration without reading one line at a time, without using a Scanner instance: 140 ms
duration when reading one line at a time with a Scanner instance: 198 ms
As you can see, not using Scanner makes your program 41% faster (integer part of (198-140)/140*100 equals 41).
package test1;
import java.io.*;
import java.util.*;
public class Test {
// Read and parse an Int from the stream: 2 operations at once
private static int readInt(InputStreamReader ir) throws IOException {
StringBuffer str = new StringBuffer();
int c;
do { c = ir.read(); } while (c < '0' || c > '9');
do {
str.append(Character.toString((char) c));
c = ir.read();
} while (!(c < '0' || c > '9'));
return Integer.parseInt(str.toString());
}
// Parsing the input step by step
private static void testing(File f) throws IOException {
InputStreamReader ir = new InputStreamReader(new BufferedInputStream(new FileInputStream(f)));
int n = readInt(ir);
int [] iVau = new int[n];
for (int i = 0; i < n; i++) iVau[i] = readInt(ir);
ir.close();
}
// Your code
private static void testing2(File f) throws IOException {
Scanner scanner = new Scanner(f);
int n = scanner.nextInt();
int[] iVau = new int[n];
scanner.nextLine();
String[] temp = scanner.nextLine().split(" ");
for(int i = 0; i < n; i++)
iVau[i] = Integer.parseInt(temp[i]);
scanner.close();
}
// Compare durations
public static void main(String[] args) throws IOException {
File f = new File("/tmp/tst.txt");
// My proposal
long t = System.currentTimeMillis();
testing(f);
System.out.println("duration without reading one line at a time, without using a Scanner instance: " + (System.currentTimeMillis() - t) + " ms");
// Your code
t = System.currentTimeMillis();
testing2(f);
System.out.println("duration when reading one line at a time with a Scanner instance: " + (System.currentTimeMillis() - t) + " ms");
}
}
NOTE: creating the input file is done this way, with bash or zsh:
echo 100000 > /tmp/tst.txt
for i in {1..100000}
do
echo -n $i" " >> /tmp/tst.txt
done
I believe this is what you're looking for. A BufferedReader can only read a line at a time, so it is necessary to split the line and cast Strings to ints.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
String[] line = br.readLine().split(" ");
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(line[i]);
}
} catch (IOException e) {
e.getStackTrace();
}
Just a thought, String.split returns an array of Strings. You say the input can be around 100,000 values. So in order to split the array in this way, String.split must be iterating through each element. Now in parsing the new array of strings to Integers you have iterated through the collection twice. You could do this in one iteration with a few small tweaks.
Scanner scanner = new Scanner(System.in);
String tmp = scanner.nextLine();
scanner = new Scanner(tmp);
for(int i = 0; scanner.hasNextInt(); i++) {
arr[i] = scanner.nextInt();
}
The reason for linking the scanner to a String instead of leaving it on System.in is so that it ends properly. It doesn't open System.in for user input on the last token. I believe in big O notation this is the difference between O(n) and O(2n) where the original snippet is O(2n)
I am not quite sure why OP has to use Integer.parseInt(s) here since Scanner can just do the parsing directly by new Scanner(File source).
Here is a demo/test for this idea:
public class NextInt {
public static void main(String... args) {
prepareInputFile(1000, 500); // create 1_000 arrays which each contains 500 numbers;
Timer.timer(() -> readFromFile(), 20, "NextInt"); // read from the file 20 times using Scanner.nextInt();
Timer.timer(() -> readTest(), 20, "Split"); // read from the file 20 times using split() and Integer.parseInt();
}
private static void readTest() {
Path inputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
try (Scanner scanner = new Scanner(new File(inputPath.toString()))) {
int n = Integer.valueOf(scanner.nextLine());
int[] iVau = new int[n];
String[] temp = scanner.nextLine().split(" ");
for (int i = 0; i < n; i++) {
iVau[i] = Integer.parseInt(temp[i]);
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
private static void readFromFile() {
Path inputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
try (Scanner scanner = new Scanner(new File(inputPath.toString()))) {
while (scanner.hasNextInt()) {
int arrSize = scanner.nextInt();
int[] arr = new int[arrSize];
for (int i = 0; i < arrSize; ++i) {
arr[i] = scanner.nextInt();
}
// System.out.println(Arrays.toString(arr));
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
private static void prepareInputFile(int arrCount, int arrSize) {
Path outputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
List<String> lines = new ArrayList<>();
for (int i = 0; i < arrCount; ++i) {
int[] arr = new int[arrSize];
for (int j = 0; j < arrSize; ++j) {
arr[j] = new Random().nextInt();
}
lines.add(String.valueOf(arrSize));
lines.add(Arrays.stream(arr).mapToObj(String::valueOf).collect(Collectors.joining(" ")));
}
try {
Files.write(outputPath, lines);
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
Locally tested it with 1_000 arrays while each array has 500 numbers, reading all the elements cost about: 340ms using Scanner.nextInt() while OP's method about 1.5ms.
NextInt: LongSummaryStatistics{count=20, sum=6793762162, min=315793916, average=339688108.100000, max=618922475}
Split: LongSummaryStatistics{count=20, sum=26073528, min=740860, average=1303676.400000, max=5724370}
So I really have doubt the issue lies in the input reading.
Since in your case you are aware of the total count of elements all that you have to do is to read X integers from the second line. Here is an example:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int count = in.nextInt();
int array[] = new int[count];
for (int i = 0; i < count; i++) {
array[i] = in.nextInt();
}
}
If this is not fast enough, which I doubt, then you could switch to the use of a BufferedReader as follows:
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int count = Integer.parseInt(in.readLine());
int array[] = new int[count];
for (int i = 0; i < count; i++) {
int nextInteger = 0;
int nextChar = in.read();
do {
nextInteger = nextInteger * 10 + (nextChar - '0');
nextChar = in.read();
} while (nextChar != -1 && nextChar != (int)' ');
array[i] = nextInteger;
}
}
In your case the input will be aways valid so this means that each of the integers will be separated by a single whitespace and the input will end up with EoF character.
If both are still slow enough for you then you could keep looking for more articles about Reading Integers in Java, Competative programming like this one: https://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/
Still my favorite language when it comes to competitions will always be C :) Good luck and enjoy!
I'm doing a java project at school and one of the tasks that I'm stuck on is correctly calculating and displaying the mean and median of rows and columns of a 2-D array. My code is in classes so I'll try to ask this question as clearly as possible. Here's my code:
//Main class
package com.company;
import java.io.*;
public class Main {
public static void main(String[] args) {
FileALL Free = new FileALL("src/com/company/text.txt");
try{
Free.FileRead();
Free.Eraser();
Free.Writing();
Free.Meanie();
Free.Median();
}
catch (Exception e){
e.printStackTrace();
}
}
}
//FILEALL Class (the class with all of the calculations, file I/O, etc.)
package com.company;
import java.io.*;
import java.util.Arrays;
public class FileALL {
//Declare variables
private static int row = 20;
private static int col = 50;
private int i;
private int j;
private int size;
private int Mean;
private int Median;
private int elements;
private static int RawData[][] = new int[row][col];
private File f;
//New method for use in the main class
//Initialize the file
public FileALL (String FileRead) {
f = new File(FileRead);
}
//Method for file input
public void FileRead () {
try {
BufferedReader reader = new BufferedReader(new FileReader(f));
String line = reader.readLine();
while ((line != null)) {
String[] Values = line.trim().split("\\s+");
for (int j = 0; j < Values.length; j++) {
RawData[i][j] = Integer.parseInt(Values[j]);
System.out.print(RawData[i][j] + " ");
}
i++;
System.out.println();
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
System.out.println("ERROR");
System.exit(0);
}
}
//This was a test for file output; I didn't really use it
/*public void FileWrite () throws IOException {
FileInputStream in = null;
FileOutputStream oot = null;
try {
in = new FileInputStream("text.txt");
oot = new FileOutputStream("OG_out.txt");
int c;
while ((c = in.read()) != -1){
oot.write(c);
}
}finally {
if (in != null){
in.close();
}
if (oot != null){
oot.close();
}
}
}*/
//Method for mean calculation
public int Meanie (){
int sum = 0;
for (i = 0; i < row; i++){
for (j = 0; j < col; j++){
if (RawData [i][j] > 0){
sum += RawData[i][j];
size++;
}
}
}
if (size != 0) {
Mean = (sum/size);
}
System.out.println("\nThe mean is " + Mean);
return Mean;
}
//Median method
public void Median (){
//Make a separate 1-D array to store the items
int [] list = new int[RawData.length*RawData[0].length];
//Initialize a new integer to keep track of the position of the items in the 1-D array
int Pos = 0;
//Iterating over the 2-D array, now adding in the new list position integer
for (i = 0; i < RawData.length; i++){
for(j = 0; j< RawData.length; j++){
list[Pos++] = RawData[i][j];
}
}
//Sort the 1-D array
Arrays.sort(list);
elements = row - Pos;
System.out.print("\nThe median is: " + MED(list));
}
//Separate method for Median
public double MED(int[]m){
int middle = m.length/2;
if (m.length%2 == 1){
return m[middle];
}
else {
return (m[middle - 1] + m[middle]) / 2;
}
}
//Method for Writing the means, medians, modes, and data sets of the array into a file created specifically for output (rows only)
//Need to figure out how to withhold the zeroes from being printed
public void Writing () throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter("src/com/company/OG_out.txt", true));
writer.write("The mean of the input array is " + Mean + "\n\n");
int a = 1;
//I'm using 'i' here because 'i' is my integer for the row counter (for the sake of simplicity)
for (i = 0; i < row; i++){
writer.write("Data set " + a + ": " + Arrays.toString(RawData[i]) + "\n\n==================================================\n\n");
writer.flush();
a++;
}
}
//This is a short method that will erase the data that was written into the output file
public void Eraser () throws IOException {
new BufferedWriter(new FileWriter("src/com/company/OG_out.txt", false));
}
}
//Text.txt file (you can enter any set of numbers in a 2-D array fashion)
1 2 3
5
6
I'm not getting any errors of exceptions but the mean sometimes comes up incorrect (which probably means it's always incorrect) and the median always comes up as 0.0. I'll also need to do the mode of the rows and columns but I don't know where to start (maybe I'll ask a separate question).
Thanks for reading and taking the time to help me out (if you choose to do so).
EDIT: I need a maximum of 20 rows and 50 columns. Also, I got the mean calculation working fine.
RawData.length is always 20 no matter how much data you actually enter. RawData[0].length is always 50. Once you allocate the array, you can't change the length downward even if you enter less data. So there will be a lot of unused elements in your array that Java initializes to 0. This means you can't use .length to loop over the array. You will need another way to tell your algorithm how many rows and columns you really have. Otherwise all those extra 0's will be part of the computation.
If you are retrieving your data from a text file with delimited line columns and the potential for basically an unspecified number of rows (file lines) then why are you declaring your RawData[][] 2D Array to a fixed number of elements when you don't really know yet what the max number of columns and rows are within the data file unless of course you are going to handle chunks of data which it does not appear you are doing. What if you have 22 or 30 lines of data in file? You'll end up with a Array Out Of Bounds Exception.
In my opinion, I think the best way to handle this if you must have a 2D Array and the data file will contain lines of varying data columns is to do a two pass read over the file.
The first pass would be used to determine the maximum number of columns in any one file line (row) and also determining the number of lines within the file which actually contain data (not a blank line - just in case it does). Determining the number of valid data lines within the data file will allow you to set the Row quantity of your 2D Array. By determining the maximum number of columns in any one line within the data file will allow you to set the Columns quantity of your 2D Array.
File f = new File("src/com/company/text.txt");
if (!f.exists()) { System.exit(0); }
// PASS 1
int maxColumns = 0;
int rows = 0;
String line = "";
try {
BufferedReader reader = new BufferedReader(new FileReader(f));
while((line = reader.readLine()) != null){
if (!line.equals("")) {
String[] values = line.trim().split(" ");
// Get the largest number of columns on any line in file.
if (values.length > maxColumns) { maxColumns = values.length; }
rows++;
}
}
reader.close();
}
catch (IOException e) {
System.out.println("IOException ERROR\n\n" + e.getMessage());
System.exit(0);
}
// Declare and initialize the rawData[][] 2D Array.
Object[][] rawData = new Object[rows][maxColumns];
The second pass read over the file would be for applying the file data into their respective 2D Array elements and because you are dealing with varying columns I would declare the 2D Array as Object since the natural data type within a text file is String and a Object type allows you to determine if a specific array element contains 'null', however, if the 2D Array is declared as a numerical data type then a empty element would contain the numerical value of zero (0) which could be a valid data value in file. Since each column element within an Object 2D Array can contain a different data type we just need to load the required ones with our desired numerical data type and leave the ones we don't need as they are:
// PASS 2
rows = 0;
line = "";
try {
BufferedReader reader = new BufferedReader(new FileReader(f));
while((line = reader.readLine()) != null){
if (!line.equals("")) {
String[] values = line.trim().split(" ");
for (int i = 0; i < values.length; i++) {
rawData[rows][i] = values[i];
}
rows++;
}
}
reader.close();
}
catch (IOException e) {
System.out.println("IOException ERROR\n\n" + e.getMessage());
System.exit(0);
}
You can always convert the Array elemental data to the desired numerical data type when iterating through and retrieving elemental data within the array. For example:
for (int i = 0; i < rawData.length; i++) {
for (int j = 0; j < rawData[0].length; j++) {
// If the 2D Array element is empty then ignore it...
if (rawData[i][j] != null) {
// otherwise get the elemental data.
int num = (int) rawData[i][j]; //Cast the object to Integer.
System.out.println("i = " + i + " | j = " + j + " | element contains: " + num);
// .....................................
// ... Do whatever you want with num ...
// .....................................
}
}
}
Of course I show all this done within a single stream or method of code but it too can be moved into individual classes...that's for you to do.
I hope this helps in some way.
I'm attempting to write a program that would read a file "data.txt" which has an undefined amount of numbers in random order, separated by line. It would add these numbers into an array and print out the numbers in one line, each separated by a comma "x, x1". Then on the next line it would print out (in the same format) the list of numbers which has been sorted from smallest to largest size.
Data type is integer.
Currently, I have coded for 3 methods which would allow the array to be sorted (I think they have no error).
I've created another method to read the file and am using a two-step process - once to figure out the number of lines in the file (I ask that this two-step process remain). This method seems to have trouble returning the "lineCount" and apparently I need to make this variable an array (which I find bizarre). How can I fix this code?
You may notice that my method for printing is empty; I have not figured out a way to print the array so that each number is separated by a comma. How do I code for this?
My code so far:
import java.util.*;
import java.io.*;
public class SortAndSearch {
public static void main(String[] args) {
readFile2Array();
printArray();
selectionSort();
printArray();
}
public static void printArray(int[] a) {
}
public static void selectionSort(int[] a) {
int minI = 0;
for (int k = 0; k < a.length - 1; ++k) {
minI = findMinIdx(a, k); // findMinIdx at k-th
swapElement(a, k, minI);// swapElement at k-th
}
}
public static int findMinIdx(int[] a, int k) {
int minIdx = k;
for (int i = k + 1; i < a.length; ++i)
if (a[i] < a[minIdx])
minIdx = i;
return minIdx;
}
public static void swapElement(int[] a, int i, int j) {
int temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static int[] readFile2Array(String fileName) {
File dat = new File("data.txt");
int lineCount = 0;
int[] a = new int[lineCount];
int i;
try{ Scanner sc = new Scanner(dat);
while (sc.hasNextLine()){ //first read to count -> int lineCount;
lineCount++;
return lineCount; //I have trouble with this line
}
while (sc.hasNextLine()){ //second read to array -> hasNext(),
a[i] = sc.nextInt();
return a;
}
}
catch (FileNotFoundException e) {
System.out.println("File cannot be opened");
e.printStackTrace();
}
}
public static int binarySearch(int[] arr, int val){
int minIdx, maxIdx, index = -1;
while(){ int middleIdx = (minIdx + maxIdx)/2;
if( arr[???] ==val){
index = middleIdx;
break } // update minIdx, maxIdx //if smaller then cut right, if larger then cut left
}
return index; }
}
The last method in the program would attempt to locate the element number of a user inputted number by using this (pseudo)code:
1. Let min = 0 and max = n-1 (where n is the array’s length)
2. If max < min, then stop: target is not present in array. return false.
3. Compute guess as the average of max and min, rounded down (so that it is an integer).
4. If array[guess] equals target, then stop. You found it! Return guess.
5. If the guess was too low, that is, array[guess] < target, then set min = guess + 1.
6. Otherwise, the guess was too high. Set max = guess - 1.
7. Go back to step 2.
How would I code for this?
I would really appreciate any help in any area of this program!
Managed to fix the first part of the code:
readFile2Array method:
public static int[] readFile2Array(String fileName) {
try {
int lineCount = 0;
Scanner sc = new Scanner(new File("data.txt"));
while (sc.hasNext()) { // first read to count -> int lineCount;
lineCount++; // second read to array -> hasNext(),
sc.nextLine();
}
sc.close();
sc = new Scanner(new File("data.txt"));
int[] x = new int[lineCount];
int n = 0;
while (sc.hasNext()) {
x[n] = Integer.parseInt(sc.nextLine());
n++;
}
sc.close();
return x;
} catch (FileNotFoundException e) {
System.out.println("File cannot be opened");
e.printStackTrace();
}
return null;
}
Print array separated by comma:
public static void printArray(int[] a) {
try {
int lineCount = 0;
Scanner sc = new Scanner(new File("data.txt"));
while (sc.hasNext()) {
lineCount++;
sc.nextLine();
}
sc.close();
for (int i = 0; i < a.length; ++i) {
System.out.print(a[i]);
if (i < lineCount-1) System.out.print(", ");
}
} catch (FileNotFoundException e) {
System.out.println("File cannot be opened");
}
System.out.println();
}
Last method is still a mystery to me though!
I agree with VGR that you haven't actually asked a question, but by reading your code I guess that you were describing what you wanted to achieve...
There are some flaws in your readFile2Array-method, which might solve the problem:
1)
int lineCount = 0;
int[] a = new int[lineCount]; //The size of a will always be 0, so you can't add anything to it, even though you are trying to do this later. Consider using a List instead, as the size of the list can increase dynamically.
2)
while (sc.hasNextLine()){ //first read to count -> int lineCount;
lineCount++;
return lineCount; //I have trouble with this line
}
//The problem is the return type: You method signature states that you will return int[], but here you are trying to return an int.
//It will also just increase lineCount once and try to return this.
3)
//Your scanning will be at the 2nd line because of 2) and not going through the entire file again. To do this you need to create a new instance of Scanner. And the int[] a has a size of 0 at this point.
while (sc.hasNextLine()){ //second read to array -> hasNext(),
a[i] = sc.nextInt();
return a;
}
So in order to solve this you should refactor your code to something like:
public static List<Integer> readFile2Array(String fileName) {
File dat = new File("data.txt");
List<Integer> a = new ArrayList<>();
try{ Scanner sc = new Scanner(dat);
while (sc.hasNextLine()){
a.add(sc.nextInt());
}
sc.close(); //Always remember to close, when done :)
System.out.println("Added " + a.size() + " lines to the list.");
return a;
} catch (FileNotFoundException e) {
System.out.println("File cannot be opened");
e.printStackTrace();
return new ArrayList<>();
}
}
What I changed:
removed the lineCount as this is implicit stored in the size of the list called a.
Changed the int[] a to a List as this always will allow adding elements by increasing its size when needed.
Removed i as was never used, only initialized.
Removed the first while-loop as we don't need to know the amount of lines that is going to be added.
Added a return-statement in the catch-closure. We need to return something (even an empty array or maybe the not-yet-finished array)
I hope this helps. :)
I'm glad you got that part working. :)
To print out the array, it will be best to use whatever data you have of the array. By calling a.length, you don't have to count the number of lines from the input again, which you are not guaranteed are still the same if the input has changed in the mean time.
So this piece of code should do the trick:
public static void printArray(int[] a) {
for (int i = 0; i < a.length; ++i) {
System.out.print(a[i]);
if (i < a.length-1) System.out.print(", ");
}
System.out.println();
}
I'm reading from a file and copying that into an array. My file has five lines of text, a sentence each. I get my output "Array size is 5" but nothing after that. If I do add a print line of the array, it gives me 5 nulls...
Can someone help explain what I did wrong? Thanks!
public static int buildArray() throws Exception
{
System.out.println("BuildArray is starting ");
java.io.File textFile; // declares a variable of type File
textFile = new java.io.File ("textFile.txt"); //reserves the memory
Scanner input = null;
try
{
input = new Scanner(textFile);
}
catch (Exception ex)
{
System.out.println("Exception in method");
System.exit(0);
}
int arraySize = 0;
while(input.hasNextLine())
{
arraySize = arraySize + 1;
if (input.nextLine() == null)
break;
}
System.out.println("Array size is " + arraySize);
// Move the lines into the array
String[] linesInRAM = new String[arraySize];// reserve the memory
int count = 0;
if (input.hasNextLine())
{
while(count < arraySize)
{
System.out.println("test");
linesInRAM[count] = input.nextLine();
System.out.println(linesInRAM[count]);
count = count + 1;
}
}
In this code
int count = 0;
if (input.hasNextLine())
The above hasNextLine will always be false as you have already read all the way through the file.
Either reset the scanner to the beginning of the file, or use a dynamic list e.g. ArrayList to add the elements to.
My Java is a bit rusty, but the basic gist of my answer is that you should create a new Scanner object so that it reads from the beginning of the file again. This is the easiest way to "reset" to the beginning.
Your code is currently not working because when you call input.nextLine() you're actually incrementing the scanner, and thus at the end of that first while() loop input is sitting at the end of the file, so when you call input.nextLine() again it returns null.
Scanner newScanner = new Scanner(textFile);
Then in the bottom of your code, your loop should look like this instead:
if (newScanner.hasNextLine())
{
while(count < arraySize)
{
System.out.println("test");
linesInRAM[count] = newScanner.nextLine();
System.out.println(linesInRAM[count]);
count = count + 1;
}
}
I'm trying to loop through a text file for integers and store integers found into an array.
Using a try-catch to determine which words are integers and which are not using InputMismatchException, removing the non-int strings from the input stream. As well as a NoSuchElementException for blank lines in the file.
My main issue is storing the integers and printing those integers in the array, in my second method :o . It also appears my loop is also recording non-ints as null as well. They aren't suppose be stored into the array.
public static void main(String[] commandlineArgument) {
Integer[] array = ReadFile6.readFileReturnIntegers(commandlineArgument[0]);
ReadFile6.printArrayAndIntegerCount(array, commandlineArgument[0]);
}
public static Integer[] readFileReturnIntegers(String filename) {
Integer[] array = new Integer[1000];
// connect to the file
File file = new File(filename);
Scanner inputFile = null;
try {
inputFile = new Scanner(file);
}
// If file not found-error message
catch (FileNotFoundException Exception) {
System.out.println("File not found!");
}
// if connected, read file
if (inputFile != null) {
// loop through file for integers and store in array
while (inputFile.hasNextLine()) {
for(int i = 0; i<array.length; i++)
{
try{
array[i] = inputFile.nextInt();
}
catch(InputMismatchException excep1)
{
String word = inputFile.next();
}
catch(NoSuchElementException excep2){
}
}
}
}
return array;
}
public static void printArrayAndIntegerCount(Integer[] array, String filename) {
//prints number of integers from file
//prints each integer in array
}
}
The approach taken in the first method is a bit flawed, since you're incrementing the i variable whether or not an integer is read.
So for example, if the file looked like this:
4
Hello
5
e
7
The beginning of your array would look like
[4, null, 5, null, 7...]
So you will end up with an array of size 1000, which has nulls at unpredictable places in there.
A slightly better approach would be this:
Keep a separate count variable that says how many integers you actually read.
Add items to the array at index count and not at i (since i just says how many lines you've looked at, whereas count will tell you how many integers you've come across).
When you're finished reading them, either
pass the count variable to the method that prints the array (so it knows only to look at the first count items), or
just copy the entire array into a new array of size count.
Example incorporating this into your code:
if(inputFile != null) {
// the number of integers we've read so far
int count = 0;
// loop through file for integers and store in array
while(inputFile.hasNextLine()) {
for(int i = 0; i < array.length; i++) {
try {
array[count] = inputFile.nextInt();
count++;
} catch(InputMismatchException excep1) {
String word = inputFile.next();
} catch(NoSuchElementException excep2) {
}
}
}
}
Then to copy into a correctly sized array,
Integer[] newArray = new Integer[count];
for(int i = 0; i < count; i++) {
newArray[i] = array[i];
}
and just return newArray instead of array.
Your print method will then simply have the same signature and functionality you'd expect:
public static void printArrayAndIntegerCount(Integer[] array, String filename) {
for(int i = 0; i < array.length; i++) {
// print the number at array[i], and whatever else you want to print
}
}
This is probably the better approach, as you can still keep all the method signatures the same, and don't need to mess around with returning multiple variables or changing global state.
Or alternatively, if you don't want to copy the relevant bits into a new array, then you could just pass the count variable somehow to your second method, and do something like
for(int i = 0; i < count; i++) {
System.out.println("\tindex = " + i + ", element = " + array[i]);
}
Key difference there is you're iterating up to count, and not up to array.length.
You would need to find a way to return that from your first method along with the array (or maybe set a static variable somewhere), and you would then need to change the signature of your second method to be
public static void printArrayAndIntegerCount(Integer[] array, int count, String filename) {
...
}
Assuming all you logic for reading integers from file are correct and also hoping this is kind of home work. Though the following implementation is not the right approach, it just solves your purpose. All we are doing here is iterating all the elements in the array until it reaches the null and keep writing them into a buffer.
public static void printArrayAndIntegerCount(Integer[] array, String filename) {
StringBuilder sb = new StringBuilder();
int count = 0;
for(Integer i : array) {
if(i != null) {
count++;
sb.append("index = ").append(i).append(", element = ").append(array[i]).append("\n");
} else {
break;
}
}
System.out.println("number of integers in file \""+filename+"\" = "+count);
System.out.println(sb);
}
Replace your catch statement with:
catch(InputMismatchException excep1)
{
String word = inputFile.next();
i-=1;
}
You were incrementing the array counter if it found a word. I have run my own test and this worked for me to fix your issue.
public static void printArrayAndIntegerCount(Integer[] array, String filename) {
String message = "";
int i = 0;
while(i < array.length && array[i]!=null){
message = message + "index = "+i+", element = "+array[i]+"\n";
i+=1;
}
System.out.println("number of integers in file \""+filename+"\" = "+i);
System.out.println(message);
}