I am not experienced wit Arrays and I am getting this error in the debug console:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
at com.company.SortTextFile.main(SortTextFile.java:28)
I've been looking in internet for how other people handle this included here in StackOverflow but I can't seem to understand why is it happening. I am trying to have this program get the input from a text file of multiple columns with 20 lines like this:
Eduardo 15 3.9 30000
And then using collection.sort to sort it using its id.
I am aware the arrays are 0-index however I don't know if I would need to specify the array size.
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import static java.lang.Double.*;
public class SortTextFile {
public static void main(String[] args) throws IOException {
// Creating BufferedReader object to read the input text file
BufferedReader reader = new BufferedReader(new FileReader(
"C:\\Users\\miche\\OneDrive\\Documentos\\University\\Algorithms\\Project\\StudentData.txt"));
// Creating ArrayList to hold Student objects
var studentRecords = new ArrayList<Student>();
// Reading Student records one by one
String currentLine = reader.readLine();
while (currentLine != null) {
String[] studentDetail = currentLine.split("\\s+");
String name = studentDetail[0];
int age = Integer.valueOf(studentDetail[1]);
double GPA = valueOf(studentDetail[2]);
int id = Integer.valueOf(studentDetail[3]);
// Creating Student object for every student record and adding it to
// ArrayList
studentRecords.add(new Student(name, age, GPA, id));
currentLine = reader.readLine();
}
// Sorting ArrayList studentRecords based on marks
Collections.sort(studentRecords, new idCompare());
// Creating BufferedWriter object to write into output text file
BufferedWriter writer = new BufferedWriter(new FileWriter(
"C:\\C:\\Users\\miche\\OneDrive\\Documentos\\University\\Algorithms\\Project\\output.txt"));
// Writing every studentRecords into output text file
for (Student student : studentRecords) {
writer.write(student.name);
writer.write(" " + student.age);
writer.write(" " + student.GPA);
writer.write(" " + student.id);
writer.newLine();
}
// Closing the resources
reader.close();
writer.close();
}
}
I made a Student class to compare the IDs.
public class Student extends SortTextFile {
String name;
int id;
int age;
double GPA;
public Student(String name, int id, double age, double GPA) {
this.name = name;
this.id = id;
this.age = (int) age;
this.GPA = GPA;
}
}
//idCompare Class to compare the marks
class idCompare implements Comparator<Student> {
#Override
public int compare(Student s1, Student s2) {
return s2.id - s1.id;}
}
Edit 1:
The text file just follows a format of Name/Age/GPA/ID:
Chipaldo 25 3.5 29000
Eduardo 15 3.9 30000
Ricardo 23 3.8 18000
Anthony 24 3.9 19000
Lombardo 29 2.0 22000
Romina 28 2.1 23000
Alex 25 3.1 13000
Sofia 21 2.2 24000
Vexler 24 2.2 25000
Albert 19 3.2 14000
John 24 3.0 15000
Melchor 14 2.9 16000
Bernardo 21 4.0 17000
Diego 19 2.1 26000
Miguelangel 25 2.0 27000
Edit 3: I managed to printout the Output in a new file. It sorted it based on age and not ID for some reason. Thank you for your help. I am going to try implement and Binary Insertion Sort to this program instead of doing Collection.sort Thanks.
If possible please be as detailed as possible with any suggestion. English is not my main language & I am slow at this. Thank you in advance
The message simply means that you have an array that only has 1 element in it and you are trying to access array element 2. This is one of those weird things in computer science (and Java as a language) because we start counting from zero rather than one, i.e. the first element in an array is indexed as studentDetail[0] and the second as studentDetail[1]. This is why you see the rather confusing "Index 1 out of bounds for length 1". The array being returned by currentLine.split(" ") only contains one string, not four, as you are expecting. You need to debug the code to find out why this is happening (from what you've provided this is not possible for someone else to answer).
your array seems to only have one entry. check if there is a problem with your string.split(" ")?
Use currentLine.split("\\s+"); This means that there may be one or more spaces or tabs or newlines between fields.
What you did will work correctly if and only if the fields are separated by one single space.
For debugging purpose print the length of the array using System.out.println(studentDetail.length);
Try This. Your code you did not closed writer thats why nothing is to in the output file.
public static void main(String[] args) throws IOException {
//Creating BufferedReader object to read the input text file
BufferedReader reader = new BufferedReader(new FileReader("E:\\Projects\\JavaBasics\\src\\data.txt"));
//Creating ArrayList to hold Student objects
var studentRecords = new ArrayList<Student>();
//Reading Student records one by one
String currentLine = null;
while ((currentLine = reader.readLine()) != null) {
if (!currentLine.isEmpty()) {
System.out.println(currentLine);
String[] studentDetail = currentLine.split(" ");
String name = studentDetail[0];
int age = Integer.valueOf(studentDetail[1]);
double GPA = Double.valueOf(studentDetail[2]);
int id = Integer.valueOf(studentDetail[3]);
studentRecords.add(new Student(name, age, GPA, id));
}
}
//Sorting ArrayList studentRecords based on marks
Collections.sort(studentRecords, new IdCompare());
//Creating BufferedWriter object to write into output text file
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(new File("E:\\Projects\\JavaBasics\\src\\dataout.txt")));
//Writing every studentRecords into output text file
for (Student student : studentRecords) {
System.out.println("Sorted :: " + student.name);
writer.write(student.name);
writer.write(" " + student.age);
writer.write(" " + student.GPA);
writer.write(" " + student.id);
writer.newLine();
}
} finally {
writer.close();
}
}
Related
The problem I am trying to solve is how to read lines from a text file and add it to an array. Then sort each element from this new array by the date that is also in each element. I will explain so its easier to understand but will explain what I am doing.
My text file (First column is name, second is Date of birth and last is the date the person died):
sarah jones,1966-12-02,2018-12-04
matt smith,1983-02-03,2020-03-02
john smith,1967-03-04,2017-04-04
I want to sort this file and output it to another file (testing by printing to console at the moment) by sorting it by the date the person died. A way I thought of doing this is to read each line and pass it to an array. Then read each element within the array, split it and then save the date the person died to another array. Then sort the array that has the death dates, loop through both arrays by seeing if the first element of the death date array matches the first element of the first line in the text file, if so then write it to another file. If not then go to the next line.
For example
BufferedReader reader = new BufferedReader(new FileReader("input_text.txt"));
PrintWriter outputStream = new PrintWriter(new FileWriter("output.txt",true));
ArrayList<String> lines = new ArrayList<String>();
ArrayList<String> substr_date = new ArrayList<String>();
String currentline = reader.readLine();
while(currentline !=null){
String a_line[] = currentline.split(",");
substr_date.add(a_line[2])
lines.add(currentline);
currentline = reader.readLine();
}
Collections.sort(substr_date);
for(String date : substr_date){
for(String line : lines){
if(line.contains(date)){
System.out.println(line);
}
}
}
I expect the output to be:
john smith,1967-03-04,2017-04-04
sarah jones,1966-12-02,2018-12-04
matt smith,1983-02-03,2020-03-02
The results are initially in order but then some lines are repeated multiple times and then the whole text file in repeated to the console and becomes a mess. I am not sure how to go about doing this. I am new to java and not sure if I asked this question properly either so if you need any more info please ask.
I would create class for objects which you can insert into a list and then define a comparator on this class which you can use to sort.
Here is an example of the class you could define:
static class DeceasedPerson {
String name;
LocalDate birthDate;
LocalDate deathDate;
DeceasedPerson(String name, LocalDate birthDate, LocalDate deathDate) {
this.name = name;
this.birthDate = birthDate;
this.deathDate = deathDate;
}
#Override
public String toString() {
return name + ", " + birthDate + ", " + deathDate;
}
}
Then you could simply load objects based on this class into a list which you sort using a comparator. Here is some sample code you can run with the class defined above:
public static void main(String[] args) {
String input =
"matt smith,1983-02-03,2020-03-02\n" +
"sarah jones,1966-12-02,2018-12-04\n" +
"john smith,1967-03-04,2017-04-04\n";
List<DeceasedPerson> deceasedPersonList = new ArrayList<>();
try (Scanner scanner = new Scanner(input)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] array = line.split(",");
DeceasedPerson deceasedPerson = new DeceasedPerson(array[0],
LocalDate.parse(array[1]), LocalDate.parse(array[2]));
deceasedPersonList.add(deceasedPerson);
}
}
deceasedPersonList.sort(Comparator.comparing(o -> o.deathDate));
deceasedPersonList.forEach(System.out::println);
}
If you run the code above using the DeceasedPerson class you should see on the console the following output:
john smith, 1967-03-04, 2017-04-04
sarah jones, 1966-12-02, 2018-12-04
matt smith, 1983-02-03, 2020-03-02
You could actually also use a TreeSet instead of a List in the main method above and achieve the same results. Here is a move concise alternative:
public static void main(String[] args) {
String input =
"matt smith,1983-02-03,2020-03-02\n" +
"sarah jones,1966-12-02,2018-12-04\n" +
"john smith,1967-03-04,2017-04-04\n";
Set<DeceasedPerson> deceasedPersonList = new TreeSet<>(Comparator.comparing(o -> o.deathDate));
try (Scanner scanner = new Scanner(input)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] array = line.split(",");
DeceasedPerson deceasedPerson = new DeceasedPerson(array[0],
LocalDate.parse(array[1]), LocalDate.parse(array[2]));
deceasedPersonList.add(deceasedPerson);
}
}
deceasedPersonList.forEach(System.out::println);
}
The way you are doing is a long shot. You can do this in much simpler way. You could pass a comparator to the Collections.sort() method like this.
Collections.sort(substr_date, new Comparator<String>{
#Override
public int compare(String str1, String str2){
String dd1 = str1.split(",")[2];
String dd2 = str2.split(",")[2];
return dd1.compareTo(dd2);
}
});
Comparing dates like this, though, is not a good approach. You should convert the date string to LocalDateTime and then use isBefore() or isAfter() to compare them. For ex,
public int compare(String str1, String str2){
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd")
LocalDateTime d1 = LocalDateTime.parse(str1.split(",")[2],format);
LocalDateTime d2 = LocalDateTime.parse(str2.split(",")[2],format);
return d1.isBefore(d2)?-1:(d1.isAfter(d2)?1:0);
}
I wanted to write a program which can print, and modify the irregular csv files. The format is as follows:
1.date
2.organization name
3. student name, id number, residence
student name, id number, residence
student name, id number, residence
student name, id number, residence
student name, id number, residence
1.another date
2.another organization name
3. student name, id number, residence
student name, id number, residence
student name, id number, residence
..........
For instance, the data may be given as follows:
1. 10/09/2016
2. cycling club
3. sam, 1000, oklahoma
henry, 1001, california
bill, 1002, NY
1. 11/15/2016
2. swimming club
3. jane, 9001, georgia
elizabeth, 9002, lousiana
I am a beginner and I have not found any viable resource online which deals with this type of problem. My main concern is, how do we iterate through the loop and identify the date and name of the club, and feed them into a array?
Please advise.
I think this should be helpful for you. Basically there should be some pattern in your messed up csv. Below is my code to arrange your csv
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter writer = new PrintWriter("file.txt", "UTF-8");
try{
//Create object of FileReader
FileReader inputFile = new FileReader("csv.txt");
//Instantiate the BufferedReader Class
BufferedReader bufferReader = new BufferedReader(inputFile);
//Variable to hold the one line data
String line;
String date="";String org ="";String student ="";
// Read file line by line and print on the console
while ((line = bufferReader.readLine()) != null) {
if(line.contains("1.")){
if(date!="" || org!=""){
writer.println(date+","+org+","+student);
student ="";
}
date = line.substring(2);
}else if(line.contains("2.")){
org = line.substring(2);
}else{
line = "("+line+")";
student += line+",";
}
System.out.println(line);
}
writer.println(date+","+org+","+student);
//Close the buffer reader
bufferReader.close();
}catch(Exception e){
System.out.println("Error while reading file line by line:" + e.getMessage());
}
writer.close();
}
This is the output you will get for this
10/09/2016, cycling club,(3. sam, 1000, oklahoma),( henry, 1001, california),( bill, 1002, NY),
11/15/2016, swimming club,(3. jane, 9001, georgia),( elizabeth, 9002, lousiana),
I am reading the file from csv.txt. while loop goes through each line of text file.all the fields are stored in a variable. When next date comes I write all of them into output file. Last line of the csv is written to file after the while loop terminates.
Try uniVocity-parsers to handle this. For parsing this sort of format, you'll find a few examples here. For writing, look here and here.
Adapting from the examples I've given, you could write:
final ObjectRowListProcessor dateProcessor = new ObjectRowListProcessor();
final ObjectRowListProcessor clubProcessor = new ObjectRowListProcessor();
final ObjectRowListProcessor memberProcessor = new ObjectRowListProcessor();
InputValueSwitch switch = new InputValueSwitch(0){
public void rowProcessorSwitched(RowProcessor from, RowProcessor to) {
//your custom logic here
if (to == dateProcessor) {
//processing dates.
}
if (to == clubProcessor) {
//processing clubs.
}
if (to == memberProcessor){
//processing members
}
};
switch.addSwitchForValue("1.", dateProcessor, 1); //getting values of column 1 and sending them to `dateProcessor`
switch.addSwitchForValue("2.", clubProcessor, 1); //getting values of column 1 and sending them to `clubProcessor`
switch.addSwitchForValue("3.", memberProcessor, 1, 2, 3); //getting values of columns 1, 2, and 3 and sending them to `memberProcessor`
setDefaultSwitch(memberProcessor, 1, 2, 3); //Rows with blank value at column 0 are members. Also get columns 1, 2, and 3 and send them to `memberProcessor`
CsvParserSettings settings = new CsvParserSettings(); //many options here, check the tutorial and examples
// configure the parser to use the switch
settings.setRowProcessor(switch);
//creates a parser
CsvParser parser = new CsvParser(settings);
//parse everying. Rows will be sent to the RowProcessor of each switch, depending on the value at column 0.
parser.parse(new File("/path/to/file.csv"));
Disclaimer: I'm the author of this library, it's open-source and free (Apache 2.0 license)
very new to Java and I have a question
I was given an text file, and asked to find the employee who earn the most, and print out their info (fName, Lname, ID)
the text file was like so:
Date of birth fName lName wage hr work emp ID
12/03/1929 Detzk Fyshe 37 49 07036310484
04/17/1930 Cauus Walden 38 52 63612537553
07/12/1930 Barth Harling 43 72 42101524036
07/16/1930 Bartl Barnhill 43 62 48621748867
I manage to find the max wage. But have no idea how to print out the info
Here my code so far:
public static void main(String[] args) {
File inFile = new File ("dataSet.txt");
ArrayList <String> inData = new ArrayList <String>();
String strline;
try
{
FileInputStream fstream = new FileInputStream(inFile);
BufferedReader br = new BufferedReader (new InputStreamReader (fstream));
while ((strline = br.readLine()) != null)
{
strline = strline.trim();
if ((strline.length()!=0)) inData.add(strline);
}
} catch (Exception e) {
System.err.println("Error CANNOT FIND FILE!");
}
// Max wage finder *start*
int maxWage=0;
for (int i=0; i<inData.size(); i++){
String [] word = inData.get(i).split(" ");
int wage=Integer.parseInt (word[3]);
int hrWork=Integer.parseInt (word[4]);
int earn = wage*hrWork;
if (earn>maxWage){
maxWage=earn;
}
}
System.out.println("Max Wage in $:"+maxWage);
//max wage finder *end*
If you're reading in employee data, then an object-oriented solution to the problem is to create an Employee class with strongly typed (dates as Dates, and integers as ints) attributes that model the contents of the file.
In addition to the instance variables that would store the actual data of each Employee, you might want to override the toString() method in the class so that the employee information can be easily output, for example to System.out. Also, you would need a getter for the "total salary" of an employee (which you calculate with wage * hrWork) so that the salaries of two employees can be compared externally, e.g. by a Comparator.
All in all, the code could look like this for the relevant parts:
private static final DateFormat FORMATTER = new SimpleDateFormat("MM/dd/yyyy");
...
List<Employee> employees = new ArrayList<Employee>();
...
// within the loop that reads the file:
String[] columns = strline.split(" ");
employees.add(new Employee(
FORMATTER.parse(columns[0]), // DOB,
columns[1], // first name
columns[2], // last name
Integer.parseInt(columns[3]), // wage
Integer.parseInt(columns[4]), // hr
columns[5]) // employee id
);
...
// after all lines have been read, output the employee with largest wage
Employee earnsMost = Collections.max(employees, new Comparator<Employee>() {
#Override
public int compare(Employee e1, Employee e2) {
return e1.getTotalSalary() - e2.getTotalSalary();
}
});
System.out.println(earnsMost + " earns most.");
So basically what I need to do is:
Read a text file like this:
[Student ID], [Student Name], Asg 1, 10, Asg 2, 10, Midterm, 40, Final, 40
01234567, Timture Choi, 99.5, 97, 100.0, 99.0
02345678, Elaine Tam, 89.5, 88.5, 99.0, 100
and present it like this (with calculations of rank and average):
ID Name Asg 1 Asg 2 Midterm Final Overall Rank
01234567 Timture Choi 99.5 97.0 100.0 99.0 99.3 1
02345678
Elaine Tam 89.5 88.5 99.0 100.0 97.4 2
Average: 94.5 92.75 99.5 99.5 98.3
Using printf() function
now this is what I have done so far:
import java.io.*;
import java.util.Scanner;
class AssignmentGrades {
public static void main(String args[]) throws Exception {
Scanner filename = new Scanner(System.in);
String fn = filename.nextLine(); //scannig the file name
System.out.println("Enter your name of file : ");
FileReader fr = new FileReader(fn+".txt");
BufferedReader br = new BufferedReader (fr);
String list;
while((list = br.readLine()) !=null) {
System.out.println(list);
}
fr.close();
}
}
So I can ask the user for the name of the file, then read it and print.
Now.. I'm stuck. I think I need to probably put it in to array and split?
String firstrow = br.readLine();
String[] firstrow = firstrow.split(", ");
something like that?.. ugh ive been stuck here for more than an hour
I really need help!! I appreciate your attention!! ( I started to learn java this week)
There are two ways for splitting the input line just read from the file
Using String object's split() method which would return an array. Read more about the split here.
StringTokenizer Class - This class can be used to divide the input string into separate tokens based on a set of delimeter. Here is a good tutorial to get started.
You should be able to get more examples using google :)
In case you want to parse integers from String. Check this.
Here I store the columns as an array of Strings and I store the record set as an ArrayList of String arrays. In the while loop if the column set is not initialized yet (first iteration) I initialize it with the split. Otherwise I add the split to the ArrayList. Import java.util.ArrayList.
String[] columns = null;
ArrayList<String[]> values = new ArrayList<String[]>();
String list;
while((list = br.readLine()) !=null) {
if (columns != null) {
columns = list.split(", ");
} else {
values.add(list.split(", "));
}
}
fr.close();
I would like to split a large text file to chunks while reading with a FileReader/BufferedReader. Each chunk will be processed separately in my downstream code (i.e generating a HashMap of information for each chunk). In order to do this, at first, I need to find a pattern to define how one chunks looks like.
Maybe someone can help me out here.
This is how the general structure of my file looks like ("//" and "\\" are not part of the file):
//
Car: Oldtimer
Ford Model T - 1908
Chevrolet Bel-Air - 1956
Mercedes-Benz W 198 - 1954
Car: Compact Car
Toyota iQ - 2008
Volkswagen Polo V - 2009
Audi A1 - 2010
Car: Special Car
Bat Mobile - 1966
Black Beauty - 1966
K.I.T.T. - 1982
Total: 3
//
One chunk should start with "Car: ABC" and end before the next "Car: XYZ" entry.
There is always one blank line before and after each "Car: ABC" entry. The file ends with "Total: n".
Just for illustration, the first chunk of my sample file will be:
//
Car: Oldtimer
Ford Model T - 1908
Chevrolet Bel-Air - 1956
Mercedes-Benz W 198 - 1954
//
So far, I tried REGEX matching to match any entries between the "Car:"-tags using Pattern.compile("Car:\\s(.*)Car:\\s") However, this approach would leave out each even chunk , e. g. the chunk starting with "Car: Compact Car".
Maybe you know other or better approaches to give each chunk an identity.
Thanks in advance.
Setting delimiter to "Car:|Total:" RE might be a solution; You have chunk in each .next() call.
Scanner sc = new Scanner(new File("file.txt"));
sc.useDelimiter("Car:|Total:");
while (sc.hasNext()) {
System.out.println(sc.next());
}
A Car is an Object. So make a class for it. Then, you know once you've seen a Car type, you know what it's type is, then use a simple String.split to parse the file.
Code:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Main {
public static class Car {
public String type;
public String name;
public int year;
public Car(String type, String name, int year) {
this.type = type;
this.name = name;
this.year = year;
}
#Override
public String toString() {
return String.format("Car: %s\tName: %s\tYear: %d", type, name, year);
}
}
public static void main(String... args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(new File("cars.txt")));
Map<String, Set<Car>> carMap = makeCars(br);
for(String key : carMap.keySet()) {
System.out.println(key);
for(Car car : carMap.get(key)) {
System.out.println(car);
}
}
}
public static Map<String, Set<Car>> makeCars(BufferedReader br) throws Exception {
String carType = null;
Set<Car> carList = null;
Map<String, Set<Car>> carMap = new HashMap<String, Set<Car>>();
int linecounter = 0;
while(br.ready()) {
String line = br.readLine();
linecounter++;
if(line.contains("Car:")) {
String[] typeSplit = line.split(": ");
if (typeSplit.length != 2) System.err.format("Error reading file on line %d%n", linecounter);
carType = typeSplit[1].trim();
carList = new HashSet<Car>();
carMap.put(carType, carList);
continue;
}
String[] carSplit = line.split(" - ");
if (carSplit.length != 2) continue;
Car newCar = new Car(carType, carSplit[0].trim(), Integer.parseInt(carSplit[1].trim()));
carList.add(newCar);
}
return carMap;
}
}
This works for me:
(Car:).*?(?=Car:|Total:)