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());
}
Related
Clarification: I have a text file with multiple lines and I want to separate specific lines into fields for an object.
I have been banging my head against a wall for about 3 days now, and I feel as if I'm overthinking this.
import java.io.*;
import java.util.*;
public class ReadFile {
public static void main(String[] args) throws FileNotFoundException {
String fileName = null;
Scanner input = new Scanner(System.in);
System.out.print("Enter file path: ");
fileName = input.nextLine();
input.close();
String fileText = readFile(fileName);
System.out.println(fileText);
}
public static String readFile(String fileName) throws FileNotFoundException {
String fileText = "";
String lineText = "";
File newFile = new File(fileName);
if (newFile.canRead()) {
try (Scanner scanFile = new Scanner(newFile)) {
while (scanFile.hasNext()) {
lineText = scanFile.nextLine();
if (lineText.startsWith("+")) {
}
else {
fileText = fileText + lineText + "\n";
}
}
} catch (Exception e) {
System.out.println(e);
}
} else {
System.out.println("No file found. Please try again.");
}
return fileText;
}
}
My goal is to take a file that looks similar to this (this is the whole file, imagine a .txt with exactly this in it):
Name of Person
----
Clothing:
Graphic TeeShirt
This shirt has a fun logo of
depicting stackoverflow and a horizon.
****
Brown Slacks
These slacks reach to the floor and
barely cover the ankles.
****
Worn Sandals
The straps on the sandals are frayed,
and the soles are obviously worn.
----
Then I need to extract the top line (e.g.: "Graphic TeeShirt") as a type of clothing the object is wearing, then "This shirt has a fun [...]" as the description of that object.
I have another .java with setters/getters/constructors, but I can't figure out how to iterate through the text file.
Edit: I know I loop through each line, but I need to create an object that has the person's name as a field, the item name (Graphic TeeShirt) as a field, then the description under the item as the next field. Then the next object will be a new object with person's name as a field, the next item (Brown Slacks) as a field, then the description as a field.
I don't know how to separate the lines in to the fields I need.
As I mentioned, the data file format is lousy, which is the real source of the problem, but your delimiters can be used to help out a little. You might approach the problem this way. Obviously don't dump your code like I've done into main but this might start you off. You still need to separate the clothing names from their descriptions but you should get the idea from the below. You can then start making a pojo out of the data.
Pass the path to your data file to this app and look out for the metadata debug outputs of 'Name' and 'Item'.
import java.util.Scanner;
import java.nio.file.Paths;
public class PersonParser {
public static void main(String[] args) {
try {
try (Scanner scPeople = new Scanner(Paths.get(args[0]))) {
scPeople.useDelimiter("----+");
int tokenCount = 0;
while (scPeople.hasNext()) {
String token = scPeople.next();
if (tokenCount % 2 == 0) {
System.out.printf("Name: %s", token);
} else {
// Parse clothing
Scanner scClothing = new Scanner(token);
scClothing.useDelimiter("\\*\\*\\*+");
while (scClothing.hasNext()) {
String item = scClothing.next();
System.out.printf("Item: %s", item);
}
}
tokenCount++;
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
The following code is according to the details in your question, namely:
The sample file in your question is the entire file.
You want to create instances of objects that have the following three attributes:
Person's name.
Name of an item of clothing.
Description of that item.
Note that rather than ask the user for the name of the file, I simply use a hard-coded file name. Also note that method toString, in the below code, is simply for testing purposes. The code also uses try-with-resources and method references.
public class ReadFile {
private static final String DELIM = "****";
private static final String LAST = "----";
private String name;
private String item;
private String description;
public void setName(String name) {
this.name = name;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public void setDescription(String description) {
this.description = description;
}
public String toString() {
return String.format("%s | %s | %s", name, item, description);
}
public static void main(String[] strings) {
try (FileReader fr = new FileReader("clothing.txt");
BufferedReader br = new BufferedReader(fr)) {
String line = br.readLine();
String name = line;
br.readLine();
br.readLine();
line = br.readLine();
String item = line;
List<ReadFile> list = new ArrayList<>();
ReadFile instance = new ReadFile();
instance.setName(name);
instance.setItem(item);
line = br.readLine();
StringBuilder description = new StringBuilder();
while (line != null && !LAST.equals(line)) {
if (DELIM.equals(line)) {
instance.setDescription(description.toString());
list.add(instance);
instance = new ReadFile();
instance.setName(name);
description.delete(0, description.length());
}
else {
if (instance.getItem() == null) {
instance.setItem(line);
}
else {
description.append(line);
}
}
line = br.readLine();
}
if (description.length() > 0) {
instance.setDescription(description.toString());
list.add(instance);
}
list.forEach(System.out::println);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
Running the above code produces the following output:
Name of Person | Graphic TeeShirt | This shirt has a fun logo ofdepicting stackoverflow and a horizon.
Name of Person | Brown Slacks | These slacks reach to the floor andbarely cover the ankles.
Name of Person | Worn Sandals | The straps on the sandals are frayed,and the soles are obviously worn.
It's not clear what you want to achieve and what is your issue exactly. You said that you can't figure out how to iterate through a text file, so let's dive into this fairly straightforward task.
In general, you have a valid, but the overcomplicated method for reading a file. Modern versions of Java provide a lot simpler methods and it's better to use them (only if you're not implementing some test task to understand how everything is working under the hood).
Please see my example below for reading a file line by line using Java NIO and Streams APIs:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter file path: ");
String fileName = input.nextLine();
input.close();
Path path = Paths.get(fileName);
try (Stream<String> lines = Files.lines(path)) {
lines.filter(line -> {
// filter your lines on some predicate
return line.startsWith("+");
});
// do the mapping to your object
} catch (IOException e) {
throw new IllegalArgumentException("Incorrect file path");
}
}
}
This should allow you to filter the lines from your files based on some predicate and later to the mapping to your POJO if you intend to do so.
If you have any other issues besides reading the file and filtering its content, please add clarification to your questions. Preferably, with examples and test data.
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();
…
I am creating a program to display restaurant reviews which are saved in a text file. The text file is read in via the DAOimpl class as shown.
public class DAOlmpl implements DAOInterface {
static final char DELIMITER=',';
/**#Override*/
public Repository load(String filename) {
Repository repository = new Repository();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String[] temp;
String line = br.readLine();
while(line!=null){
temp=line.split(Character.toString(DELIMITER));
String name = stripQuotes(temp[0]);
String location = stripQuotes(temp[1]);
Restaurant restaurant = new Restaurant(name, location) {};
int lines = Integer.parseInt(temp[2]);
ArrayList<Review> review = new ArrayList<>();
for (int i=0; i<lines; i++) {
restaurant.addReviews(review);
}
repository.add(restaurant);
line = br.readLine();
}
br.close();
} catch (IOException ex) {
Logger.getLogger(DAOlmpl.class.getName()).log(Level.SEVERE, null, ex);
}
return repository;
}
}
and then is transfered over to the Restaurant class using this method.
public void addReviews(Review review) {
this.reviewsCollection.add(review);
}
However, I cant seem to get it over into the Restruant class as its in the form of an arraylist and not an object. I've treid many wayas to correct it, but cant get it working
If I read it correct, may this could be the Solution:
List<Review> reviews = new ArrayList<>();
for (Review review : reviews) {
restaurant.addReview(review);
}
and for the function
public void addReview(Review review) {
this.reviewsCollection.add(review);
}
So you add each Review separately what is in your list.
But you don't put any Review object in to your List so your list will be empty in this example.
Hope it helps.
Some logic is missing from your code. I noticed that you did not create any Review object. To remedy this, you could create Review objects, one after another and call the Restaurant.addReviews(Review); method for each Review object created. This could be done in the for loop as shown below:
for (int i=0; i<lines; i++) {
// Create a review object
//
Review review = createReview();
// Add the review object
//
restaurant.addReviews(review);
}
The above would obviate the need for the ArrayList of reviews.
In addition, The method to add reviews shown below...
public void addReviews(Review review) {
this.reviewsCollection.add(review);
}
...could be broken down into 2 methods. One method named: addReview to add a single Review and the other named: addReviews to add many Reviews. Notice the letter 's' missing from the former and added to the later method name. Use the 's' to signify adding multiple... See both methods below:
public void addReviews(List<Review> reviews) {
this.reviewsCollection.addAll(reviews);
}
public void addReview(Review review) {
this.reviewsCollection.add(review);
}
There are more observations. But I simply answered the immediate pressing (i.e your question).
Now, lets put it all together:
public class DAOlmpl implements DAOInterface {
static final char DELIMITER=',';
/**#Override*/
#Override
public Repository load(String filename) {
Repository repository = new Repository();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line = br.readLine();
while(line!=null){
Restaurant restaurant = createRestaurantHavingReviews(line)
repository.add(restaurant);
line = br.readLine();
}
br.close();
} catch (IOException ex) {
Logger.getLogger(DAOlmpl.class.getName()).log(Level.SEVERE, null, ex);
}
return repository;
}
public Restaurant createRestaurantHavingReviews(String line) {
String [] temp=line.split(Character.toString(DELIMITER));
Restaurant restaurant = createRestaurant(temp);
int lines = Integer.parseInt(temp[2]);
for (int i=0; i<lines; i++) {
Review review = createReview(temp);
restaurant.addReview(review);
}
return restaurant;
}
public Restaurant createRestaurant(String[]temp) {
String name = stripQuotes(temp[0]);
String location = stripQuotes(temp[1]);
Restaurant restaurant = new Restaurant(name, location) {};
return restaurant;
}
public Review createReview(String[]temp) {
throw new UnsupportedOperationException("Please implement me!");
}
}
The above code is more readable and if you implement the public Review createReview(String[]temp) method above.. we could take it up from there if you have more questions.
Hope this helps.
I am trying to open a csv file using openCSV, iterate over every column and if the userID is different write a new JavaBean pair at the end of the file.
The problem is that the reader only checks the first column of my file and not the whole file. While created, the file contains only a header and nothing else. The program will check every column and if the sudoID is different it will write it to the file. If the sudoID in the first line is equal to the the one imported from my main class it will recognise it and not write it. But if this -same- sudoID is in the second row it will not recognise it and will write it again.
For instance, if my CSV looks like this it will work:
"Patient_id Pseudo_ID",
"32415","PAT106663926"
If it looks like this it will re-write the sudoID:
"Patient_id Pseudo_ID",
"32416","PAT104958880"
"32415","PAT106663926"
Thanks!
My Code:
public class CSVConnection {
#SuppressWarnings({ "deprecation", "resource", "rawtypes", "unchecked" })
public String getID(String sID,String pseudoID) throws IOException, CsvDataTypeMismatchException, CsvRequiredFieldEmptyException{
try {
CsvToBean csv = new CsvToBean();
String csvFilename = "CsvFile.csv";
Writer writer= new FileWriter(csvFilename,true);
CSVReader csvReader = new CSVReader(new FileReader(csvFilename),',','"',1);
ColumnPositionMappingStrategy strategy = new ColumnPositionMappingStrategy();
strategy.setType(PatientCSV.class);
String[] columns = new String[] {"patID","pseudoID"};
strategy.setColumnMapping(columns);
//Set column mapping strategy
StatefulBeanToCsv<PatientCSV> bc = new StatefulBeanToCsvBuilder<PatientCSV>(writer).withMappingStrategy(strategy).build();
List patList = csv.parse(strategy, csvReader);
for (Object patObj : patList) {
PatientCSV pat = (PatientCSV) patObj;
if(((PatientCSV) patObj).getPatID().equals(sID)){
return pat.getPseudoID();
}
else
{
PatientCSV pat1 = new PatientCSV();
pat1.setPatID(sID);
pat1.setPseudoID(pseudoID);
patList.add(pat1);
/*Find a way to import it to the CSV*/
bc.write(pat1);
writer.close();
return pseudoID;
}
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void main(String [] args) throws IOException, CsvDataTypeMismatchException, CsvRequiredFieldEmptyException{
CSVConnection obj = new CSVConnection();
String sID="32415";
String pseudoID="PAT101830150";
obj.getID(sID,pseudoID);
}
}
and the Java Bean :
public class PatientCSV {
private String patID;
private String pseudoID;
public String getPatID() {
return patID;
}
public void setPatID(String patID) {
this.patID = patID;
}
public String getPseudoID() {
return pseudoID;
}
public void setPseudoID(String pseudoID) {
this.pseudoID = pseudoID;
}
public PatientCSV(String patID, String pseudoID) {
super();
this.patID = patID;
this.pseudoID = pseudoID;
}
public PatientCSV() {
super();
// TODO Auto-generated constructor stub
}
public String toString()
{
return "Patient [id=" + patID + ", pseudoID=" + pseudoID + "]";
}
}
Lets inspect your for loop
for (Object patObj : patList) {
PatientCSV pat = (PatientCSV) patObj;
if(((PatientCSV) patObj).getPatID().equals(sID)){
return pat.getPseudoID();
}
else
{
PatientCSV pat1 = new PatientCSV();
pat1.setPatID(sID);
pat1.setPseudoID(pseudoID);
patList.add(pat1);
/*Find a way to import it to the CSV*/
bc.write(pat1);
writer.close();
return pseudoID;
}
}
So in the case you mention it is not working as expected, meaning that the line that matches your input is the second line:
"Patient_id Pseudo_ID",
"32416","PAT104958880"
"32415","PAT106663926"
So you call: getID("32415", "PAT106663926")
What happens in your loop is:
You take the first element of your csv patients, the one with id: 32416,
check if it matches with the id given as input to your method, 32415.
It does not match so it goes to the else part. There it creates the new patient (with the same patID and pseudoID as the 2nd row of your csv) and stores it in the file.
So by now you should have 2 entries in your csv with the same data "32415","PAT106663926".
I think that this is the error, in your for loop you should check against all entries if there is a match, and then create the patient and store it to the csv.
An example:
PatientCSV foundPatient = null;
for (Object patObj : patList) {
PatientCSV pat = (PatientCSV) patObj;
if(((PatientCSV) patObj).getPatID().equals(sID)){
foundPatient = pat;
}
}
if (foundPatient == null) {
foundPatient = new PatientCSV();
foundPatient.setPatID(sID);
foundPatient.setPseudoID(pseudoID);
patList.add(foundPatient);
/*Find a way to import it to the CSV*/
bc.write(foundPatient);
writer.close();
}
return foundPatient.getPseudoID();
P.S. The above example is written very quickly, just to give you the idea what needs to be done.
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.