I have three CSV files with data that is linked by a string of numbers, I've created a 2d array to store all the data together and have one of the csv files, the data in the other files is not in the same order so I can't simply read line 1 of the file into the first row of the array.
Here's my code
public class grades {
public static void main(String[] args) throws FileNotFoundException
{
int rowc = 0;
String inputLine = "";
String[][] students = new String[10][6];
//Get scanner instance
Scanner scanner = new Scanner(new File("/IRStudents.csv"));
//Set the delimiter used in file
scanner.useDelimiter(",");
while (scanner.hasNextLine()) {
inputLine = scanner.nextLine();
String [] line = inputLine.split(",");
for (int x = 0; x < 2; x++) {
students[rowc][x] = line[x];
}
if (rowc < 9) {
rowc++;
}
else {
break;
}
}
System.out.println(Arrays.deepToString(students));
scanner.close();
Scanner input = new Scanner(new File("/IR101.csv"));
input.useDelimiter(",");
while (input.hasNext()) {
inputLine = input.nextLine();
String[] line = inputLine.split(",");
for (int i = 0; i < 1; i++) {
System.out.println(line[0]);
System.out.println(students[0][i]);
if (line[0].equals(students[0][i])) {
students[2][i] = line[0];
}
}
}
System.out.println(Arrays.deepToString(students));
}
}
I know a lot of it's not very tidy or efficient, but I'd rather it was working. Anyway, how would I loop through the file and add each item to the 3rd column of the array where the corresponding string is that links them?
Thanks.
I hope i understood your problem correctly.
In your case, you could load the 3rd csv into memory and then loop through the arrays (a for inside another for) and check the keys of one array that matches the key on the other (strings that links them) and bind them.
tip: you could initialize the students attributes like this:
students[rowc] = line;
Related
SOF. I have a problem which I'm having some difficulty with.
The following code is supposed to sieve through the file line-by-line, utilizes the StringTokenizer effectively to get the Car Class's Make, Model, Year, and Mileage (in that order) and store those in a car object, which I then add to 2 ArrayLists, one of which is "sorted" by Make and the other which is "unsorted".
The selectionSort I wrote initially worked with Strings which didn't work for obvious reasons.
Can this be fixed by making the selectionSort work with objects (Cars)? Eclipse recommended that to me and the current selectionSort is a product of that.
public void readFile(String file) throws FileNotFoundException //an object array that takes in string files
{
try {
File myFile = new File(file); //converts the parameter string into a file
Scanner scanner = new Scanner(myFile); //File enables us to use Scanner
String line = scanner.nextLine(); //reads the current line and points to the next one
StringTokenizer tokenizer = new StringTokenizer(line, ","); //tokenizes the line, which is the scanned file
int tokenCount = new StringTokenizer(line, ",").countTokens(); //counts the tokens
while (tokenizer.hasMoreTokens()){
if(tokenCount > 4) {
System.out.println(" Not 4 tokens");
}
else {
String CarMake = tokenizer.nextToken(); //since car is in order by make, model, year, and mileage
String CarModel = tokenizer.nextToken();
int CarYear1 = Integer.parseInt(tokenizer.nextToken());
int CarMileage1 = Integer.parseInt(tokenizer.nextToken()); //converts the String numbers into integers
Car cars = new Car(CarMake, CarModel, CarYear1, CarMileage1); //since the car has a fixed order
arraylist.add(cars); //add the cars to the unsorted array
}
}
scanner.close(); //close the scanner
} catch (FileNotFoundException f){
f.printStackTrace();
}
arraylist2.addAll(arraylist);
selectionSort(arraylist2);
}
public static void selectionSort(ArrayList<Car> arraylist) //Selection sort using strings
{
for (int i = 0; i <= arraylist.size(); i++)
{
// Look through the unsorted strings (those at j or higher) for the one that is first in order
int min = i;
for (arraylist[i].getMake.compareTo(arraylist[min].getMake) < 0) { //use the inherent string compareTo
min = k;
}
String temp = arraylist[i].getMake; //swapping
arraylist[i].getMake = arraylist[min].getMake;
arraylist[min] = temp;
}
}
Any help would be greatly appreciated.
The reason your new code doesn't work is that you're swapping only the makes of the Cars, not the full Car objects.
It should be:
Car temp = arraylist[i]; //swapping
arraylist[i] = arraylist[min];
arraylist[min] = temp;
I am struggling to use scanner class to read in a text file while skipping the blank lines.
Any suggestions?
Scanner sc = new Scanner(new BufferedReader(new FileReader("training2.txt")));
trainingData = new double[48][2];
while(sc.hasNextLine()) {
for (int i=0; i<trainingData.length; i++) {
String[] line = sc.nextLine().trim().split(" ");
if(line.length==0)
{
sc.nextLine();
}else{
for (int j=0; j<line.length; j++) {
trainingData[i][j] = Double.parseDouble(line[j]);
}
}
}
}
if(sc.hasNextLine())
{
sc.nextLine();
}
sc.close();
I am currently trying to get it working like this. But it is not working
Scanner sc = new Scanner(new BufferedReader(new FileReader("training.txt")));
trainingData = new double[48][2];
while(sc.hasNextLine()) {
String line = sc.nextLine().trim();
if(line.length()!=0)
{
for (int i=0; i<trainingData.length; i++) {
String[] line2 = sc.nextLine().trim().split(" ");
for (int j=0; j<line2.length; j++) {
trainingData[i][j] = Double.parseDouble(line2[j]);
}
}
}
}
return trainingData;
while(sc.hasNextLine()) {
for (int i=0; i<trainingData.length; i++) {
String[] line = sc.nextLine().trim().split(" ");
You can't just check the scanner once to see if it has data and then use a loop to read the lines of data. You can't assume that you have 48 lines of data just because you define your array to hold 48 lines of data.
You need to go back to the basics and learn how to read data from a file one line at a time and then you process that data.
Here is a simple example to get you started:
import java.util.*;
public class ScannerTest2
{
public static void main(String args[])
throws Exception
{
String data = "1 2\n\n3 4\n\n5 6\n7 8";
// First attempt
System.out.println("Display All Lines");
Scanner s = new Scanner( data );
while (s.hasNextLine())
{
String line = s.nextLine();
System.out.println( line );
}
// Second attempt
System.out.println("Display non blank lines");
s = new Scanner( data );
while (s.hasNextLine())
{
String line = s.nextLine();
if (line.length() != 0)
{
System.out.println( line );
}
}
// Final attempt
String[][] values = new String[5][2];
int row = 0;
System.out.println("Add data to 2D Array");
s = new Scanner( data );
while (s.hasNextLine())
{
String line = s.nextLine();
if (line.length() != 0)
{
String[] digits = line.split(" ");
values[row] = digits;
row++;
}
}
for (int i = 0; i < values.length; i++)
System.out.println( Arrays.asList(values[i]) );
}
}
The example uses a String variable to simulate data from a file.
The first block of code is how you simply read all lines of data from the file. The logic simply:
invokes the hasNextLine() method so see if there is data
invokes the nextLine() method to get the line of data
display the data that was read
repeats steps 1-3 until there is no data.
Then next block of code simply adds an "if condition" so that you only display non-blank data.
Finally the 3rd block of code is closer to what you want. As it reads each line of data, it splits the data into an array and then adds this array to the 2D array.
This is the part of code you will need to change. You will need to convert the String array to an double array before adding it to your 2D array. So change this code first to get it working. Then once this works make the necessary changes to your real application once you understand the concept.
Note in my code how the last row displays [null, null]. This is why it is not a good idea to use arrays because you never know how big the array should be. If you have less that 5 you get the null values. If you have more than 5 you will get an out of bounds exception.
Try adding this to your code:
sc.skip("(\r\n)");
It will ignore blank lines. For More information: Scanner.skip()
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!
Hey guys and gals hope everyones Saturday night is going as swimmingly (preferably more) than mine own.
I'm a java noob so bear with me.
We are told to export the an excel sheet from Open Office into a .txt (Tab Delimited)
It ends up looking like this
1 2 3
4 5 6
7 8 9
10 11 12
Where all values are separated by a tab.. (something I haven't encountered yet and are Integer values)
I can see one option, as i type this as I could capture each line, then string split the line by?? whitespace or /t ... and then assign the values to the respective positions in the [30][10] array...
(which ends up being a .csv and load it into java.
So Job 1 is to populate a 2D array with the files from the tab delimited file.
import java.util.Scanner;
import java.io.File;
import java.util.Arrays;
public class Nitrogen
{
private int elevations[][] = null;
private String filename = "location.txt";
public Nitrogen()
{
int [][]elevations = new int[30][10];
}
public void run()
{
try{
File file = new File(filename);
Scanner input = new Scanner(file);
int rows = 30;
int columns = 10;
int[][] elevations = new int[30][10];
for(int i = 0; i < rows; ++i)
{
for(int j = 0; j < columns; ++j)
{
if(input.hasNextInt())
{
elevations[i][j] = input.nextInt();
}
}
for (int h=0; h < rows; h++) {
for (int g=0; g < columns; g++)
System.out.print(elevations[h][g] +" ");
}
System.out.println("");
}
}
catch (java.io.FileNotFoundException e) {
System.out.println("Error opening "+filename+", ending program");
System.exit(1);}
}
public static void main(String[] args)
{
Nitrogen n = new Nitrogen();
n.run();
}
}
So, this prints out 30 lines of line 1, then a line of 0's on top of 29 lines of line 2, then 2 lines of 0's on top of 28 lines of line 3, You get the point....all moving left to right.
Not quite sure....tis getting late and i might give up for the evening.
Alright!! Here is the solution... persistence pays of thanks for the help everyone
public void populate()
{
try{
File file = new File(filename);
Scanner input = new Scanner(file);
int rows = 30;
int columns = 10;
int[][] elevations = new int[30][10];
for(int i = 0; i < rows; ++i){
for(int j = 0; j < columns; ++j)
{
if(input.hasNextInt())
{
elevations[i][j] = input.nextInt();
}
}
}
for (int h=0; h < rows; h++){ //This was just to show I had it
for (int g=0; g < columns; g++) { //in there correctly
System.out.print(elevations[h][g] +" ");
}
System.out.println(""); }
}
catch (java.io.FileNotFoundException e) {
System.out.println("Error opening "+filename+", ending program");
System.exit(1);}
}
If you are trying to print out the array, I would suggest the following amendment to your code:
for (int h=0; h < rows; h++) {
for (int g=0; g < columns; g++)
System.out.print(elevations[h][g] + " ");
}
System.out.println("");
}
The above will produce an output such as:
Row1, Row1, Row1
Row2, Row2, Row2
Because it prints out the columns, with a space in between each element, then a new line between the rows.
I know this is a simple assignment for a class, but if you can use Collections for IO, please do so. It makes the code much more generally usable.
If you want to read values from a tab delimited file (in OpenOffice, this is called a {Tab} delimited CSV file in the Save dialog window), the easiest you can do, is split each line according to a tab, like this:
public static ArrayList<ArrayList<Integer>> readFile(String filename) throws IOException {
File file = new File(filename);
BufferedReader br = new BufferedReader(new FileReader(file));
ArrayList<ArrayList<Integer>> list = new ArrayList<>(); // list of lines
String buffer;
while ((buffer = br.readLine()) != null) {
String[] splitted = buffer.split("\t"); // split the lines by tabs
ArrayList<Integer> line = new ArrayList<>();
for (String str : splitted) {
line.add(Integer.parseInt(str)); // cast and add all the integers to a list
}
list.add(line); // add the line to the list of lines
}
return list;
}
We are able to create a list of lines, with each line containing the Integer values from the text file. Now, we need to create a 2D list out of it, so concatenate all the values from every line to the line before.
public static ArrayList<Integer> concatenateAll(ArrayList<ArrayList<Integer>> lines) {
ArrayList<Integer> result = new ArrayList<>(); // create an empty 2D list for all the values
for(ArrayList<Integer> line : lines) {
result.addAll(line); // add all the values from every line to the 2D list
}
return result;
}
We can create a 2D list of all the values in the file. To use these two methods, we need to invoke them like this:
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> lineList = null;
try {
lineList = readFile("table.csv");
} catch (IOException ioe) {
ioe.printStackTrace();
}
ArrayList<Integer> allLines = concatenateAll(lineList);
System.out.println(allLines);
}
If we absolutely need an array, we can add this at the end:
Integer[] linesArray = new Integer[allLines.size()];
allLines.toArray(linesArray);
System.out.println(Arrays.toString(linesArray));
For non-class assignments, here's a one liner:
private string[][] Deserialize(string data)
{
return ( from string line
in data.Split('\r\n')
select line.Split(' ')
).ToArray();
}
I have the following problem... I want to read unknown number of strings from the input. So, I made an arraylist 'words' and added all the strings from the input. Then I wanted to convert this arraylist into simpler String array 'wordsarray'(String[])... As I did that I wanted to check if everything is ok (if words are saved in 'wordsarray') so I
tried to print out the whole array... but it doesn't give me what I wanted... It seems like my code does not work. Where is the problem?
Thanks for your help
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
List<String> words = new ArrayList<String>();
while(sc.hasNextLine()) {
words.add(sc.nextLine());
}
String[] wordsarray = new String[words.size()];
for(int i = 0; i < words.size(); i++) {
wordsarray[i] = words.get(i);
}
for(int i = 0; i < words.size(); i++) {
System.out.println(wordsarray[i]);
}
}
There is a precooked method to do what you are trying to do:
ArrayList<String> words = new ArrayList<String>();
String[] array = words.toArray(new String[words.size()]);
But your code seems correct, are you sure everything is fetched fine inside the ArrayList?
By your comment I guess that the problem is the fact that you don't place everything inside a loop. This code:
while(sc.hasNextLine()) {
words.add(sc.nextLine());
}
works only once. If you keep inserting words and pressing enter you are already outside the loop because the Scanner already reached a point in which it didn't have any more lines to fetch.
You should do something like:
boolean finished = false;
while (!finished) {
while(sc.hasNextLine()) {
String line = sc.nextLine();
if (line.equals(""))
finished = true;
else
words.add(sc.nextLine());
}
}
}
This works fine for me:
import java.util.*;
public class a
{
public static void main (String [] args) throws Exception
{
Scanner sc = new Scanner(System.in);
List<String> words = new ArrayList<String>();
while(words.size () < 3 && sc.hasNextLine ()) {
String s = sc.nextLine();
System.out.println ("Adding " + s);
words.add(s);
}
String[] wordsarray = words.toArray(new String [] {});
for(int i = 0; i < words.size(); i++) {
System.out.println("Printing ..." + wordsarray[i]);
}
}
}
Output:
java a
1
Adding 1
2
Adding 2
3
Adding 3
Printing ...1
Printing ...2
Printing ...3