Reading A File and Storing It In An Object - java

I am trying to read from a file and store the contents into an object called ToDoList(from what I assume is under the GetItem method). Then I am supposed to allow the user to add on to the list. But I am lost on how to create the object and print it.
public class ToDoList {
private ToDoItem[] items;
ToDoItem td = new ToDoItem();
String inputline;
Scanner keyboard = new Scanner(System.in);
int i = 0;
String[] stringArray = new String[100];
private void setItems(ToDoItem[] items) throws FileNotFoundException {
File file = new File("ToDoItems.txt");
Scanner ReadFile = new Scanner(file);
while (ReadFile.hasNext()) {
String ListString = ReadFile.nextLine();
stringArray[100] = (ListString);
}
}
private ToDoItem[] getItems() {
return items;
}
public void addItem(int id, String description) {
stringArray[100] = (td.getId() + td.getDescription());
}
public String[] getAddItem() throws FileNotFoundException {
try (PrintWriter fout = new PrintWriter(new File("ToDoItems.txt"))) {
do {
System.out.println("add to the list? [y/n]");
inputline = keyboard.nextLine();
if ("y".equals(inputline)) {
i++;
stringArray[i] = (td.getId() + ". " + td.getDescription() + "\n");
fout.print(stringArray[i]);
} else {
System.out.println("Here is the list so far:");
}
} while ("y".equals(inputline));
return stringArray;
}
}
#Override
public String toString() {
return "ToDoList{" + "items=" + getItems()
+ '}';
}
I am supposed to use the "getAddItem" method to allow the user to add to the list. But I can't figure out how to add an array to an object. let alone make the object.

A little code to expand on what pininfarina said and to help you get going.
You need a ToDoItem class. Something like this:
public class ToDoItem {
private String id;
private String description;
public ToDoItem(String id, String description) {
this.id = id;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Then you need a ToDoList class to hold each item. You backed yours with an Array, but I used an ArrayList:
public class ToDoList {
private ArrayList<ToDoItem> items = new ArrayList<ToDoItem>();
public ToDoList(String fileName) throws FileNotFoundException {
File file = new File(fileName);
Scanner scanner = new Scanner(file);
try {
while (scanner.hasNext()) {
String nextLine = scanner.nextLine();
StringTokenizer tokenizer = new StringTokenizer(nextLine, ",");
String id = tokenizer.nextToken();
String description = tokenizer.nextToken();
items.add(new ToDoItem(id, description));
}
} finally {
scanner.close();
}
}
public void setItems(ArrayList<ToDoItem> newItems) {
this.items.addAll(newItems);
}
public List<ToDoItem> getItems() {
return items;
}
public void addItem(ToDoItem item) {
items.add(item);
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ToDoList{");
for (ToDoItem item : items) {
builder.append(item.getId() + "," + item.getDescription() + "\n");
}
builder.append("}");
return builder.toString();
}
}
This includes a constructor that reads the file and parses out items. Each line in the file must be something like "1,something" because the tokenizer uses the comma. Note that the Scanner actually destroys the file as it reads it. You might consider using some sort of FileReader instead.
Finally you need a main class to run it. Something like this:
public class RunIt {
private static Scanner keyboard = new Scanner(System.in);
public static void main(String[] args) throws FileNotFoundException {
ToDoList list = new ToDoList("ToDoItems.txt");
try (PrintWriter fout = new PrintWriter(new File("ToDoItems.txt"))) {
String inputLine;
do {
System.out.println("add to the list? [y/n]");
inputLine = keyboard.nextLine();
if ("y".equals(inputLine)) {
System.out.println("enter a to-do using the format 'id,description'");
StringTokenizer tokenizer = new StringTokenizer(keyboard.nextLine(),
",");
String id = tokenizer.nextToken();
String description = tokenizer.nextToken();
list.addItem(new ToDoItem(id, description));
} else {
System.out.println("Here is the list so far:");
System.out.println(list);
}
} while ("y".equals(inputLine));
}
}
}
Please note that there is a lot of room for improvement here (exception handling, more robust file reading, etc), but this should get you started.

You are asking a broad question. Here's some design tips for you.
Create your collection class. This could be named ToDoList. Then create the attributes and behaviors of this class. One attribute will be the collection variable of your to do list items. You can use, List, ArrayList, etc. Behaviors could be add, remove, reorder, and etc.
Create your item class. Again with the attributes and behaviors. Attributes could include what to do, date, importance level, etc.
When you read your file, have your program to instantiate your ToDoItem class for every line, item etc. then save them into the previously created container class which is your ToDoList.
You can use your ToDoList class' addItem method (behavior) to have your users add more items into your ToDoList. If you want to keep the list even after your program closes. You can create a database to store your objects.
Good luck.

Related

Java - parsing a 2nd csv file to override a value

I have two csv files. One shows all crime data including City, State, Population etc. The other shows State and Abbreviation. I want to have the state set as the abbreviation, currently I have some very long code and I'm thinking there is definitely a better way at setting it based on the abbreviation csv file.
My main class:
public class StartApp {
public static ArrayList<CityCrime> crimes = new ArrayList<CityCrime>();
public static ArrayList<String> cities = new ArrayList<String>();
/**
* Start point for app. Directs the reads from file and shows the menu
* #param args
*/
public static void main(String[] args) {
try {
readCrimeData("crimeUSA.csv");
System.out.println("Total cities read: " + getTotalCities());
showMenu();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Reads the crime data for each city from entered file
* Adds the CityCrime objects to the crimes ArrayList
*/
public static void readCrimeData(String fromFile) {
File file = new File(fromFile);
FileReader fileReader;
BufferedReader bufferedReader;
String crimeInfo;
String[] stats;
try {
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
crimeInfo = bufferedReader.readLine();
crimeInfo = bufferedReader.readLine();
do {
CityCrime crime = new CityCrime(); // Default constructor
stats = crimeInfo.split(",");
{
if (stats[0] != null) {
crime.setCity(stats[0]);
}
if (stats[1] != null) {
crime.setState(stats[1]);
}
if (stats[2] != null) {
if (Integer.parseInt(stats[2]) >= 0) {
crime.setPopulation(Integer.parseInt(stats[2]));
}
}
if (stats[3] != null) {
if (Integer.parseInt(stats[3]) >= 0) {
crime.setMurder(Integer.parseInt(stats[3]));
}
}
if (stats[4] != null) {
if (Integer.parseInt(stats[4]) >= 0) {
crime.setRobbery(Integer.parseInt(stats[4]));
}
}
if (stats[5] != null) {
if (Integer.parseInt(stats[5]) >= 0) {
crime.setAssault(Integer.parseInt(stats[5]));
}
}
if (stats[6] != null) {
if (Integer.parseInt(stats[6]) >= 0) {
crime.setBurglary(Integer.parseInt(stats[6]));
}
}
if (stats[7] != null) {
if (Integer.parseInt(stats[7]) >= 0) {
crime.setLarceny(Integer.parseInt(stats[7]));
}
}
if (stats[8] != null) {
if (Integer.parseInt(stats[8]) >= 0) {
crime.setMotorTheft(Integer.parseInt(stats[8]));
}
}
crime.setTotalCrimes(Integer.parseInt(stats[3]), Integer.parseInt(stats[4]), Integer.parseInt(stats[5]), Integer.parseInt(stats[6]), Integer.parseInt(stats[7]), Integer.parseInt(stats[8]));
}
crimes.add(crime);
System.out.println(crime);
crimeInfo = bufferedReader.readLine();
} while (crimeInfo != null);
fileReader.close();
bufferedReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* For each crime, add the city to the cities ArrayList and return the count
*/
public static int getTotalCities() {
for(CityCrime crime : crimes) {
cities.add(crime.getCity());
}
int cityCount = cities.size();
return cityCount;
}
/**
* Displays the menu
* User can select which function they want to run
* #throws IOException
*/
#SuppressWarnings("unlikely-arg-type")
public static void showMenu() throws IOException {
#SuppressWarnings("resource")
Scanner menuSelect = new java.util.Scanner(System.in);
System.out.println("1. Display all crime stats by city");
System.out.println("2. Display all crime stats by selected city");
System.out.println("3. Display the murder stats by selected state ");
System.out.println("4. Display highest crime city - all crimes");
System.out.println("5. Display each state (in alphabetical order with the number of car thefts ");
System.out.println("6. Write / export all cities in descending order of Robbery rate ");
System.out.println("7. Quit");
System.out.println("Enter option 1-7");
#SuppressWarnings("resource")
Scanner scanner = new Scanner(System.in);
int option = Integer.parseInt(menuSelect.next());
if(option<1 || option>7 ) {
System.out.println("Invalid input.");
return;
}
switch (option) {
case 1:
displayAllCityCrimeStats();
break;
case 2:
System.out.println("Enter city");
String cityOption = menuSelect.next();
displayCrimeStatsByCity(cityOption);
break;
case 3:
System.out.println("Enter state");
String stateOption = menuSelect.next();
displayMurdersByState(stateOption);
break;
case 4:
displayHighestCrimeStats();
break;
case 5:
displayStateCarThefts();
break;
case 6:
writeToFile("Robbery.csv");
break;
case 7:
return;
default:
option = Integer.parseInt(scanner.next());
}
}
My CityCrime file. It is a mess right now as I don't know what the right direction to go in is. I have cut down the setStates, there are 52 in reality so it's pretty long:
public class CityCrime {
//Instance variables
private String city;
private String state;
private int population;
private int murder;
private int robbery;
private int assault;
private int burglary;
private int larceny;
private int motorTheft;
public int totalCrimes;
public static ArrayList<CityState> abbreviations = new ArrayList<CityState>();
public String fromFile = ("C:/Users/ebeck/Downloads/StateAbbreviations.csv");
public static void main(String[] args) {
}
public static void readAbbrevData(String fromFile) {
File file = new File(fromFile);
FileReader fileReader;
BufferedReader bufferedReader;
String abbrevInfo;
String[] stats;
try {
fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader);
abbrevInfo = bufferedReader.readLine();
abbrevInfo = bufferedReader.readLine();
do {
CityState abbrev = new CityState(); // Default constructor
stats = abbrevInfo.split(",");
{
if (stats[0] != null) {
abbrev.setState(stats[0]);
}
if (stats[1] != null) {
abbrev.setAbbreviation(stats[1]);
}
}
abbreviations.add(abbrev);
System.out.println(abbrev);
abbrevInfo = bufferedReader.readLine();
} while (abbrevInfo != null);
fileReader.close();
bufferedReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
if(state.equalsIgnoreCase("ALABAMA")) {
this.state = "AL";
}
else if(state.equalsIgnoreCase("ALASKA")) {
this.state = "AK";
}
else if(state.equalsIgnoreCase("ARIZONA")) {
this.state = "AR";
}
else if(state.equalsIgnoreCase("ARKANSAS")) {
this.state = "AR";
}
else if(state.equalsIgnoreCase("CALIFORNIA")) {
this.state = "CA";
}
else if(state.equalsIgnoreCase("COLORADO")) {
this.state = "CO";
}
else if(state.equalsIgnoreCase("CONNECTICUT")) {
this.state = "CT";
}
//etc
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
public int getMurder() {
return murder;
}
//etc
}
I created a CityState file, however may be unnecessary:
public class CityState {
private String state;
private String abbreviation;
public static void main(String[] args) {
}
public String getState() {
return state;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public void setState(String state) {
this.state = state;
}
}
A couple reasons I want to change how I've set up the get state is 1. for my Junit test for state:
#Test
public void testValidState() {
CityCrime crimes = new CityCrime();
crimes.setState(state);
assertEquals(crimes.getState(), state);
}
I was getting the error:
expected: <A[K] but was: <A[LASKA]> if I set the state to "Alaska"
Then if I set it to "AK" I got the error:
expected: but was:
and 2. it doesn't look great either and I want to learn a better way
Thankyou for your help I appreciate it
Edit:
For each crime, if the state in CityCrimes csv file is equal to the state in the StatesAbbreviations file, then set the state as the abbreviation in the StatesAbbreviations file and return
Okay, first of all, I think it's better to split the data from the data parsing.
One class = one representation. Here CityCrime has two goals: represent quantity of crimes in a City (the goal indicated by the class name) and parse the abbreviation list. So I think it's better to create a new class whose goal is the parsing of your abbreviations.
Next, there is a consistency problem: you have a function that parse your abbreviation CSV, but you have also a list of if to "convert" a state name to a state abbreviation (setState function). There is, according to me, two ways to do this:
Define State as a type
Define State as resource
State as a type
The advantage of this method is to benefit from a strong typing. Indeed, with your setState solution, you define a State as a String, and you have to check if the passed value is correct (succession of if). Moreover, as it remains a String, you have no guarantee that the value returned by getState is formatted well (you have to trust all the functions that write on state variable).
So the solution here is to defined State as a type, using, for example, Enumeration.
public enum State {
ALABAMA("AL"),
ALASKA("AK"),
ARIZONA("AR"),
ARKANSAS("AR"),
CALIFORNIA("CA"),
COLORADO("CO"),
CONNECTICUT("CT");
private String abbreviation;
State(String abbreviation) {
this.abbreviation = abbreviation;
}
public String getAbbreviation() {
return abbreviation;
}
}
An enum is a particular type of class. Indeed, this one is not direclty instanciable (you can't do new State("foo")). The accepted instances for this type are defined as an enumeration, at the start of the class (ALABAMA, ALASKA...). So State.ALABAMA has for type State and State.ALABAMA.getAbbrevation() returns AL.
This solution works only if the set of all your states is closed, so if your have a fixed number of state.
In this situation, your state variable would have for type State, and your setState function would take a State variable. This is strong typed, because you can't pass a value that is not valid to the function (except null).
How to convert a State name to a State variable ?
Enumeration classes have a valueOf(String name) function. The parameter is the identifier of the enum constant (ALABAMA, ALASKA) as a String, and the returned value is the enum constant as State. If any enum constant was found, an IllegalArgumentException is throwed. This solution works well, but the string must correspond exactly to the identifier (case included).
If you want to do a similar function, but ignoring case, you can use values function that returns an array of all State values (State[]). For example:
public static State valueOfIgnoreCase(String name) {
for(var state: State.values())
if(state.name.equals(name)) // name function return the exact identifier of the state
return state;
return null; // Or throw IllegalArgumentException
}
This function can be create in the State class.
State as a resource
Another solution is to define State as a resource, that is, in an external file (or resource file). The advantage is you can add new State dynamically, without having to modify the program code. It's the solution you use with your parser.
For this solution, the parser is in a separated class.
Instead of put all your State in an List, you can put in a Map:
public class AbbreviationParser {
public static Map<String, State> parseState(InputStream stream) throws IOException { // InputStream is better than String or File, because it abstract the type of input (can works with a simple file, a network stream, a text downloaded from Internet...)
final var map = new HashMap<String, State>();
final var reader = new BufferedReader(new InputStreamReader(stream)); // Define a reader on the stream then bufferize it for better performance
reader.readLine();
String line;
while((line = reader.readLine()) != null) { // As long as there is an unread line
var array = line.split(",");
if(array.length == 2) {// Important, because if your line does not contain a comma, your actual code will crash at "array[1]"
var state = new State();
state.setState(array[0]);
state.setAbbreviation(array[1]);
map.put(state.getState(), state);
} else {
//TODO define a behavior if the line is not valid
}
}
reader.close();
stream.close();
return map;
}
To call this function for a File:
parseState(new FileInputStream(fromFile)); // FileInputStream is an implementation of InputStream for File
To secure your State from external instantiation, you can put the State constructor in package-only scope, and place this class and AbbreviationParser in the same package. Like this, only the class on the same package (so AbbreviationParser) can instantiate State, and you are thus sure not to have an incorrect value passed to your setState(State state):
public class State {
private String state;
private String abbreviation;
State() {}
public String getState() {
return state;
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation(String abbreviation) {
this.abbreviation = abbreviation;
}
public void setState(String state) {
this.state = state;
}
}
Even if you prefer the first method for your State, I recommend you to take inspiration from my parser for your first CSV parser and to isolate it in a separated class.
You want to replace certain values in the first CSV file with corresponding values in the second CSV file. The code will be extremely long if you use Java to perform the association.
But it is easy to do the coding job using Java’s open-source package SPL. One line of code is enough:
+
1
=file("crimeUSA.csv").import#ct().switch(State,file("StateAbbreviations.csv").import#ct():State).new(City,State.Abbreviation: StateAbbreviation,Population,Murder,Robbery,Assault,Burglary,Larceny,MotorTheft,TotalCrimes)
SPL offers JDBC driver to be invoked by Java. Just store the above SPL script as abbr.splx and invoke it in Java as you call a stored procedure:
…
Class.forName("com.esproc.jdbc.InternalDriver");
con= DriverManager.getConnection("jdbc:esproc:local://");
st=con.prepareCall("call abbr()");
st.execute();
…
Or execute the SPL string within a Java program as we execute a SQL statement:
…
st = con.prepareStatement("==file(\"crimeUSA.csv\").import#ct().
switch(State,file(\"StateAbbreviations.csv\").import#ct():State)
.new(City,State.Abbreviation,Population,Murder,Robbery,Assault
,Burglary,Larceny,MotorTheft,TotalCrimes)");
st.execute();
…

Java method to read text file and return ArrayList type object

public static void main(String[] args)
{
ArrayList <Locations> LocationsList = readFile("Locations.csv", "Locations");
//ArrayList <Movies> MoviesList = readFile("Movies.csv", "Movies");
//ArrayList <Operators> OperatorsList = readFile("Operators.csv", "Operators");
//ArrayList <PersonCategory> PersonCategoryList = readFile("PersonCategory.csv", "PersonCategory");
}
public static ArrayList readFile(String fileName, String whichFile)
{
ArrayList list = new ArrayList();
try
{
BufferedReader br = new BufferedReader(new FileReader(fileName));
String indata;
int line = 0;
while((indata=br.readLine())!=null)
{
StringTokenizer st = new StringTokenizer(indata,",");
if(line != 0)
{
if(whichFile.equals("Locations"))
{
int id = Integer.parseInt(st.nextToken());
String city = st.nextToken();
if(city.charAt(0) == '"')
{
String c = st.nextToken();
city = city.substring(1,city.length()) +"," +c.substring(0,c.length()-1);
}
int stateId = Integer.parseInt(st.nextToken());
Locations x = new Locations(id, city, stateId);
list.add(x);
}
else if(whichFile.equals("Movies"))
{
int id = Integer.parseInt(st.nextToken());
String name = st.nextToken();
int ratingId = Integer.parseInt(st.nextToken());
Movies x = new Movies(id, name, ratingId);
list.add(x);
}
}
line++;
}
br.close();
}
catch (FileNotFoundException fnfe){System.out.println(fnfe.getMessage());}
catch (IOException io){System.out.println(io.getMessage());}
catch (Exception e){System.out.println(e.getMessage());}
return list;
}
I'm trying to create a method that will read a text file and can return an ArrayList type object for the usage of multiple Class. With my code above, it can run successfully.
But, there are lines of warning like:
"The expression of type ArrayList needs unchecked conversion to conform to ArrayList<Locations>"
How do I fix this?
Try this.
public static <T> ArrayList<T> readFile(String fileName, Function<String[], T> converter) throws IOException {
ArrayList<T> result = new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName))) {
String line = reader.readLine();
String[] fields = line.split(",");
T object = converter.apply(fields);
result.add(object);
}
return result;
}
and define the converters which convert a CSV line to an object.
static Locations convertLocations(String[] fields) {
int id = Integer.parseInt(fields[0]);
String city = fields[1];
if (city.charAt(0) == '"') {
String c = fields[2];
city = city.substring(1, city.length()) + "," + c.substring(0, c.length() - 1);
}
int stateId = Integer.parseInt(fields[3]);
Locations x = new Locations(id, city, stateId);
return x;
}
static Movies convertMovies(String[] fields) {
/* Make Movies object from fields */
}
and combine them.
ArrayList<Locations> LocationsList = readFile("Locations.csv", fields -> convertLocations(fields));
ArrayList<Movies> MoviesList = readFile("Movies.csv", fields -> convertMovies(fields));
You need to create the proper generics-based ArrayList using for example: new ArrayList<Location>()
You could solve this by passing a class to readFile like this:
public static <T> ArrayList<T> readFile(....., Class<T> clazz)
{
ArrayList<T> list = new ArrayList<T>();
...
}
This is my final code that I took from #saka1029 and made some adjustments so that it will read every line in the file except the first one.
public static <T> ArrayList<T> readFile(String fileName, Function<String[], T> converter)
{
ArrayList <T> list = new ArrayList<>();
try
{
BufferedReader br = new BufferedReader(new FileReader(fileName));
br.readLine();
String inData;
while((inData=br.readLine()) != null)
{
String[] fields = inData.split(",");
T object = converter.apply(fields);
list.add(object);
}
br.close();
}
catch (FileNotFoundException fnfe){System.out.println(fnfe.getMessage());}
catch (IOException io){System.out.println(io.getMessage());}
catch (Exception e){System.out.println(e.getMessage());}
return list;
}
And this is my version of the correction of the method convertLocations from #saka1029 answer.
static Locations convertLocations(String[] fields)
{
int id = Integer.parseInt(fields[0]);
String city = fields[1];
int stateId;
if (city.charAt(0) == '"')
{
String c = fields[2];
city = city.substring(1, city.length()) + "," + c.substring(0, c.length() - 1);
stateId = Integer.parseInt(fields[3]);
}
else
stateId = Integer.parseInt(fields[2]);
Locations x = new Locations(id, city, stateId);
return x;
}
Essentially, you need to specify the type parameter for generic class ArrayList.
Since you are adding objects created from different classes to the same list, you could create an interface, say, MyInterface
public interface MyInterface {
....
}
All classes you return from readFile must implement this interface. For eg.
public class Movies implements MyInterface {
....
}
Now, you can add type parameter MyInterface at appropriate places:
public static void main(String[] args) {
ArrayList<MyInterface> LocationsList = readFile("Locations.csv", "Locations");
....
}
public static ArrayList<MyInterface> readFile(String fileName, String whichFile) {
ArrayList<MyInterface> list = new ArrayList<>();
....
}
Added below info based on reply
You may in fact choose to leave the interface blank, but then you will have to explicitly cast objects to concrete classes to do anything useful.
You could cast each object when needed
MyInterface myInterfaceObject = locationsList.get(0)
Locations locations = Locations.class.cast(myInterfaceObject);
OR
MyInterface myInterfaceObject = locationsList.get(0)
Locations locations = (Locations) myInterfaceObject;
OR You could write a list converter function for each concrete type
public class ListConverter {
public ArrayList<Locations> toLocationsArraylist(ArrayList<MyInterface> inList) {
ArrayList<Locations> outList = new ArrayList<>();
for (MyInterface listItem : inList) {
outList.add((Locations) listItem);
}
return outList;
}
}
and then
public static void main(String[] args) {
ArrayList<MyInterface> myInterfaceList = readFile("Locations.csv", "Locations");
ArrayList<Locations> locationList = ListConverter.toLocationsArraylist(myInterfaceList);
}
If you do consider using this solution, then consider renaming MyInterface more appropriately, say, to CsvRecord, or anything domain-specific.

Separating Parsing Method

I'm creating a program which handles SKU's. I currently have two classes in my program, the SKU class is the main class and a Store class in which an ArrayList is initialised and SKU objects are stored in the array. I currently have a method in my SKU class which takes input from a file, parses the data and stores the data using a String tokenizer in the objects variables and adds the objects to the array in the Store class. The problem I'm facing is that I'm wanting to separate the parsing method in the SKU class so that it simply reads from a line, and then have a separate method which takes a file input for the parser and finally update my Store class so that it initialises the products with the parsed data. Please, can you help me in regards to this?
My parsing method in the SKU class is currently as follows:
public void parser() {
try {
// create a Buffered Reader object instance with a FileReader
BufferedReader br = new BufferedReader(new FileReader("products.txt"));
// read from first line from the text file
String fileRead = br.readLine();
// skip first line from sample file as it contains headings
int lineNumber = 0;
// loop until all lines are read
while (fileRead != null)
{
if(lineNumber == 0) {
lineNumber++;
continue;
}
lineNumber++;
// use string.split to load a string array with the values from each line of
// the file, using a tab as the delimiter
String[] tokenize = fileRead.split("\t");
// assume file is made correctly
// and make temporary variables for the three types of data
String tempProductCode = tokenize[0];
String tempDescription = tokenize[1];
BigDecimal tempPrice = new BigDecimal(tokenize[2]);
// create temporary instance of SKU object
// and load with three data values
SKU tempObj = new SKU();
tempObj.setProductCode(tempProductCode);
tempObj.setDescription(tempDescription);
tempObj.setPrice(tempPrice);
// add to array list
Store.mySkuArrayList.add(tempObj);
// read next line before looping
// if end of file reached
fileRead = br.readLine();
}
// close file stream
br.close();
}
// handle exceptions
catch (FileNotFoundException fnfe)
{
System.out.println("file not found");
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
My Store class is as follows:
public class Store {
public static ArrayList<SKU> mySkuArrayList = new ArrayList<SKU>();
public void addSKU(SKU sku) {
mySkuArrayList.add(sku);
}
Split your code to three separate classes. SkuFile class represents text file where sku codes is stored, this class knows how to every sku entry stored and able to parse it. Sku class contains data. Store class contains
list of Sku and accept SkuFile in it's constructor.
class SkuFile {
private String path;
SkuFile(String path) {
this.path = path;
}
List<Sku> readAllSku() {
ArrayList<Sku> result = new ArrayList<>();
try {
List<String> lines = Files.readAllLines(new File(path).toPath());
for(String skuLine : lines) {
result.add(parseFrom(skuLine));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return result;
}
private Sku parseFrom(String data){
String[] tokenize = data.split("\t");
productCode = tokenize[0];
description = tokenize[1];
price = new BigDecimal(tokenize[2]);
return new Sku(productCode, description, price);
}
}
class Sku {
private String code;
private String description;
private BigDecimal price;
Sku(String code, String description, BigDecimal price) {
this.code = code;
this.description = description;
this.price = price;
}
//getters setters methods
}
class Store {
private List<Sku> skus;
Store(SkuFile file) {
skus = file.readAllSku();
}
}
class Test {
public static void main(String[] args) {
Store store = new Store(new SkuFile("products.txt"));
}
}
One way to handle this is by making the parse method return a list of tokenizers(e.g. List tokenizeList) and a second method which takes that list as input and populates the SkuArrayList
Possible implementation of the parser method
public List<String[]> parser() {
List<String[]> tokenizeList = new ArrayList<>();
try {
... /*file opening logic*/
while (fileRead != null)
{
.../*line counting logic*/
String[] tokenize = fileRead.split("\t");
tokenizeList.add(tokenize);
fileRead = br.readLine();
}
// close file stream
br.close();
}// handle exceptions
catch (FileNotFoundException fnfe)
{
System.out.println("file not found");
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
return tokenizeList;
}
Possible implementation of the populate store method
public void populateStore(List<String[]> tokenizeList) {
for(String[] tokenize: tokenizeList) {
String tempProductCode = tokenize[0];
String tempDescription = tokenize[1];
BigDecimal tempPrice = new BigDecimal(tokenize[2]);
SKU tempObj = new SKU();
tempObj.setProductCode(tempProductCode);
tempObj.setDescription(tempDescription);
tempObj.setPrice(tempPrice);
// add to array list
Store.mySkuArrayList.add(tempObj);
}
}
And the main method from where you call these two methods
public void foo() {
populateStore(parser());
}

How to sort from text file and write into another text file Java

I have this textfile which I like to sort based on HC from the pair HC and P3
This is my file to be sorted (avgGen.txt):
7686.88,HC
20169.22,P3
7820.86,HC
19686.34,P3
6805.62,HC
17933.10,P3
Then my desired output into a new textfile (output.txt) is:
6805.62,HC
17933.10,P3
7686.88,HC
20169.22,P3
7820.86,HC
19686.34,P3
How can I sort the pairs HC and P3 from textfile where HC always appear for odd numbered index and P3 appear for even numbered index but I want the sorting to be ascending based on the HC value?
This is my code:
public class SortTest {
public static void main (String[] args) throws IOException{
ArrayList<Double> rows = new ArrayList<Double>();
ArrayList<String> convertString = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new FileReader("avgGen.txt"));
String s;
while((s = reader.readLine())!=null){
String[] data = s.split(",");
double avg = Double.parseDouble(data[0]);
rows.add(avg);
}
Collections.sort(rows);
for (Double toStr : rows){
convertString.add(String.valueOf(toStr));
}
FileWriter writer = new FileWriter("output.txt");
for(String cur: convertString)
writer.write(cur +"\n");
reader.close();
writer.close();
}
}
Please help.
When you read from the input file, you essentially discarded the string values. You need to retain those string values and associate them with their corresponding double values for your purpose.
You can
wrap the double value and the string value into a class,
create the list using that class instead of the double value alone
Then sort the list based on the double value of the class using either a Comparator or make the class implement Comparable interface.
Print out both the double value and its associated string value, which are encapsulated within a class
Below is an example:
static class Item {
String str;
Double value;
public Item(String str, Double value) {
this.str = str;
this.value = value;
}
}
public static void main (String[] args) throws IOException {
ArrayList<Item> rows = new ArrayList<Item>();
BufferedReader reader = new BufferedReader(new FileReader("avgGen.txt"));
String s;
while((s = reader.readLine())!=null){
String[] data = s.split(",");
double avg = Double.parseDouble(data[0]);
rows.add(new Item(data[1], avg));
}
Collections.sort(rows, new Comparator<Item>() {
public int compare(Item o1, Item o2) {
if (o1.value < o2.value) {
return -1;
} else if (o1.value > o2.value) {
return 1;
}
return 0;
}
});
FileWriter writer = new FileWriter("output.txt");
for(Item cur: rows)
writer.write(cur.value + "," + cur.str + "\n");
reader.close();
writer.close();
}
When your program reads lines from the input file, it splits each line, stores the double portion, and discards the rest. This is because only data[0] is used, while data[1] is not part of any expression.
There are several ways of fixing this. One is to create an array of objects that have the double value and the whole string:
class StringWithSortKey {
public final double key;
public final String str;
public StringWithSortKey(String s) {
String[] data = s.split(",");
key = Double.parseDouble(data[0]);
str = s;
}
}
Create a list of objects of this class, sort them using a custom comparator or by implementing Comparable<StringWithSortKey> interface, and write out str members of sorted objects into the output file.
Define a Pojo or bean representing an well defined/organized/structured data type in the file:
class Pojo implements Comparable<Pojo> {
private double value;
private String name;
#Override
public String toString() {
return "Pojo [value=" + value + ", name=" + name + "]";
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* #param value
* #param name
*/
public Pojo(double value, String name) {
this.value = value;
this.name = name;
}
#Override
public int compareTo(Pojo o) {
return ((Double) this.value).compareTo(o.value);
}
}
then after that: read->sort->store:
public static void main(String[] args) throws IOException {
List<Pojo> pojoList = new ArrayList<>();
BufferedReader reader = new BufferedReader(new FileReader("chat.txt"));
String s;
String[] data;
while ((s = reader.readLine()) != null) {
data = s.split(",");
pojoList.add(new Pojo(Double.parseDouble(data[0]), data[1]));
}
Collections.sort(pojoList);
FileWriter writer = new FileWriter("output.txt");
for (Pojo cur : pojoList)
writer.write(cur.toString() + "\n");
reader.close();
writer.close();
}
Using java-8, there is an easy way of performing this.
public static void main(String[] args) throws IOException {
List<String> lines =
Files.lines(Paths.get("D:\\avgGen.txt"))
.sorted((a, b) -> Integer.compare(Integer.parseInt(a.substring(0,a.indexOf('.'))), Integer.parseInt(b.substring(0,b.indexOf('.')))))
.collect(Collectors.toList());
Files.write(Paths.get("D:\\newFile.txt"), lines);
}
Even better, using a Method reference
public static void main(String[] args) throws IOException {
Files.write(Paths.get("D:\\newFile.txt"),
Files.lines(Paths.get("D:\\avgGen.txt"))
.sorted(Test::compareTheStrings)
.collect(Collectors.toList()));
}
public static int compareTheStrings(String a, String b) {
return Integer.compare(Integer.parseInt(a.substring(0,a.indexOf('.'))), Integer.parseInt(b.substring(0,b.indexOf('.'))));
}
By using double loop sort the items
then just comapre it using the loop and right in the sorted order
public static void main(String[] args) throws IOException {
ArrayList<Double> rows = new ArrayList<Double>();
ArrayList<String> convertString = new ArrayList<String>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("C:/Temp/AvgGen.txt"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String s;
try {
while((s = reader.readLine())!=null){
String[] data = s.split(",");
convertString.add(s);
double avg = Double.parseDouble(data[0]);
rows.add(avg);
}
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileWriter writer = new FileWriter("C:/Temp/output.txt");;
Collections.sort(rows);
for (double sorted : rows) {
for (String value : convertString) {
if(Double.parseDouble(value.split(",")[0])==sorted)
{
writer.write(value +"\n");
}
}
}

sort line by last name and in order

Ok so I have this code so far that sorts by job position, now It also needs to be sort by last name and in alphabetical order. Ive managed to make it by sort by position then give the average salary and total.
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
public class faculty {
private static final String ASSISTANT = "assistant";
private static final String ASSOCIATE = "associate";
private static final String FULL = "full";
public static void main(String[] args) {
FileInputStream filestream;
BufferedReader reader;
PrintWriter writer;
String line;
double totalAssistant = 0;
double totalAssociate = 0;
double totalFull = 0;
try {
filestream = new FileInputStream("Faculty List.txt");
reader = new BufferedReader(new InputStreamReader(filestream));
writer = new PrintWriter("test.txt");
List<String> assistantList = new ArrayList<String>();
List<String> associateList = new ArrayList<String>();
List<String> fullList = new ArrayList<String>();
while ((line = reader.readLine()) != null) {
String[] split = line.split(" ");
double value = Double.parseDouble(split[split.length - 1]);
String type = split[split.length - 2];
if (ASSISTANT.equals(type)) {
assistantList.add(line);
} else if (ASSOCIATE.equals(type)) {
totalAssociate += value;
associateList.add(line);
} else if (FULL.equals(type)) {
totalFull += value;
fullList.add(line);
}
}
writeInFileOutput(writer, totalAssistant, assistantList);
writeInFileOutput(writer, totalAssociate, associateList);
writeInFileOutput(writer, totalFull, fullList);
reader.close();
writer.close();
} catch (IOException e) {
System.out.println(e);
} finally {
reader = null;
filestream = null;
writer = null;
}
}
private static void writeInFileOutput(PrintWriter writer, double totalSalary, List<String> listLines) {
for (String assistant : listLines) {
writer.append(assistant).append("\n");
}
writer.append("-------\n");
writer.append("Total Salary:$").append(String.valueOf(totalSalary)).append("\n");
writer.append("Average Salary: $")
.append(String.valueOf(totalSalary / listLines.size())).append(" \n\n");
}
}
Output
Pablo Bailey EDUC associate 68757.00
Lonnie Williamson GENS associate 134777.00
Raymond Page EDUC associate 120150.00
Wallace Fitzgerald BUSN associate 40889.00
Juana Robbins SOBL associate 93669.00
Steven Hall SOBL associate 117532.00
Melissa Davis EDUC associate 132186.00
Karla Valdez BUSN associate 16385.00
Melba Luna HLTH associate 70358.00
Sonja Washington HLTH associate 59302.00
Julio Diaz HLTH associate 102641.00
Virgil Briggs PAC associate 40936.00
Terrell Sherman EDUC associate 161595.00
Jorge Scott CSIS associate 124175.00
Tanya Duncan BUSN associate 178894.00
Troy Cannon BUSN associate 58890.00
-------
Total Salary: $3645049.0
Average Salary: $104144.25714285714
that's what my current output is, its sorted by rank. I now have to add to the list sort by last name first followed by first name alphabetically.this is just a small sample of the output cause the text file is pretty long.
The new lines can be added to the output.
I would make your stuff much more object oriented. So this means: introduce a new object employee that has some fields like following example:
public class Employee {
private String firstName;
private String familyName;
private String department;
private Enum jobPosition;
private double salary;
// Put constructor and some getters and setters for your field here
}
public enum JobPosition {
assistant,
associate,
full
}
When reading your input, split into the fields you need to create your employee and create 1 list with all your employees. Because you now have objects instead of a String containing multiple properties of one employee you can easily sort your objects on each property you want.
I'd use Aster's approach, and then either make Employee implement Comparable<Employee>, or make a Comparator<Employee>.
With Comparable<Employee>
public class Employee implements Comparable<Employee> {
#Override
public int compareTo(Employee e) {
int deptResult = this.department.compareToIgnoreCase(e.department);
if (deptResult != 0) {
return deptResult;
}
familyNameResult = this.familyName.compareToIgnoreCase(e.familyName);
if (familyNameResult != 0) {
return familyNameResult;
}
return this.firstName.compareToIgnoreCase(e.firstName);
}
}
With Comparator<Employee>
public class EmployeeComparator implements Comparator<Employee> {
#Override
public int compare(Employee e1, Employee e2) {
int deptResult = e1.getDepartment().compareToIgnoreCase(e2.getDepartment());
if (deptResult != 0) {
return deptResult;
}
familyNameResult = e1.getFamilyName().compareToIgnoreCase(e2.getFamilyName());
if (familyNameResult != 0) {
return familyNameResult;
}
return e1.getFirstName().compareToIgnoreCase(e2.getFirstName());
}
}

Categories