I have many albums in txt file and i want to read each line in the file while i read. I should check if the line start with Uppercase letter. So that means I should create new object of type Album, and if the line star with "0" that means is track and I should create new object of type Track and so on for an e.g of album which i want tack it from the file and store it in my java program:
Pink Floyd : Dark Side of the Moon
0:01:30 - Speak to me
0:06:48 - Brain Damage
.
.
etc.
And this is my code the file have 13 albums and each has many tracks with the period of every track.
if(Character.isUpperCase(line.charAt(0))==true) {
String[] token=line.split(":");
artistName=token[0];
albumTitle=token[1];
}
else {
tracks.add(new Track(line));
count2++;
}
album = new Album(artistName,albumTitle,tracks);
albumCollection.add(album);
so how to let the program understand that the start of album's tracks and end and then pass the array list of track to album object.
Thank
Your question is a bit difficult to understand but, I give it a try and imagined the scenario. I assume that you have already created Album and Track classes and everything works. I assume that your albums file looks as follow:
Pink Floyd : Dark Side of the Moon
0:01:30 - Speak to me
0:06:48 - Brain Damage
Another artist: Album name
0:02:33 - Whatever
0:16:21 - Blah Blah
Third artist: Album name
0:02:33 - X
0:16:21 - Y
0:02:33 - Z
0:16:21 - A
What you have to do is start reading the file line by line, which I believe that you are doing somewhere in the code that we cannot see. For each line you have the following condition which is fine
//you don't need to add == true in the if condition
if (Character.isUpperCase(line.charAt(0))) {
//Album found
} else {
//Track found
}
Every time you read a line. If Album found then you initialize an Album object and store it its artist, title and an empty list of tracks. Every time a track if found, check if the Album object is not null (if not null then it is current album) and retrieve its track list, add the new track to it and set the track list back to the Album object.
I have written the following code, assuming you have majority of it which we cannot see in this question. Go through the code and you will understand how a line is read and how an object of Album is created, how tracks are created and stored in the album. To test the following solution, copy/paste it in file same as class name and execute it, make sure you have the album.txt file containing the album.
import java.util.List;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
class Track {
String track;
public Track(String track) {
this.track = track;
}
//overriding toString() method for Track class
public String toString() {
return track;
}
}
class Album {
String artistName;
String albumTitle;
List < Track > tracks = new ArrayList < Track > ();
//Album Constructor
public Album(String artistName, String albumTitle) {
this.artistName = artistName;
this.albumTitle = albumTitle;
}
public List < Track > getTracks() {
return tracks;
}
public void setTracks(List < Track > tracks) {
this.tracks = tracks;
}
//overriding the toString method for Album
public String toString() {
StringBuilder album = new StringBuilder();
album.append("Artist name: " + artistName + "\n");
album.append("\n Album title : " + albumTitle + "\n\n");
for (int i = 0; i < tracks.size(); i++) {
album.append("\n Track " + (i + 1) + ":" + tracks.get(i).toString());
}
return album.toString();
}
}
public class ReadAlbums {
public static void main(String[] args) {
List < Album > albumsCollection = new ArrayList < Album > ();
BufferedReader in = null;
try { in = new BufferedReader(new FileReader("albums.txt"));
String line;
List < Track > currentTracks = new ArrayList < Track > ();
Album album = null;
while ((line = in .readLine()) != null) {
//no need to put == true in the if condition
if (Character.isUpperCase(line.charAt(0))) {
//Album found
String[] token = line.split(":");
//If the not the first ever album then add the previous album to the collection
if (album != null) {
albumsCollection.add(album);
}
//new album object is created with artist name and album title
album = new Album(token[0], token[1]);
//new empty track list is added to the album object
album.setTracks(new ArrayList < Track > ());
} else {
//Track found
//retrieve the track from Album album
currentTracks = album.getTracks();
//Add the track to the list of tracks obtained from album
currentTracks.add(new Track(line));
//add the updated track list back to the album object
album.setTracks(currentTracks);
}
}
//add the last album in the album collections
if(album != null) {
albumsCollection.add(album);
}
//close the input stream
in.close();
} catch (IOException e) {}
System.out.println("albums : " + albums.toString());
}
}
You get the following output:
albums : [Artist name: Pink Floyd
Album title : Dark Side of the Moon
Track 1:0:01:30 - Speak to me
Track 2:0:06:48 - Brain Damage, Artist name: Another artist
Album title : This is the second album
Track 1:0:02:33 - Whatever
Track 2:0:16:21 - Blah Blah, Artist name: Third artist
Album title : This is the third album
Track 1:0:02:33 - X ]
To print the data read from file back in the same format. You need to to loop through albums and for each album retrieve the list of tracks and then print the track.
for(int i = 0; i < albumsCollection.size();i++) {
Album album = albumsCollection.get(i);
System.out.println(album.getArtistName() + ":" + album.getAlbumTitle());
List<Tracks> tracks = album.getTracks();
for(int j = 0; j < tracks.size(); j++) {
System.out.println(tracks[j].toString());
}
}
yes it like this.
The Dave Brubeck Quartet : Take Five
0:06:44 - Blue Rondo a la Turk
0:07:22 - Strange Meadow Lark
0:05:24 - Take Five
0:04:16 - Pick Up Sticks
Goldfrapp : Supernature
0:03:24 - Ooh La La
0:03:25 - Lovely 2 C U
0:04:41 - Ride a White Horse
If you really want to do it like this and if your file REALLY always has this exact structure, a quick and dirty solution would be this:
ArrayList<Track> tracks = new ArrayList<Track>();
ArrayList<Album> albumCollection = new ArrayList<Album>();
Album album;
String artistName;
String albumTitle;
String[] token;
BufferedReader br = new BufferedReader(new FileReader("albums.txt"));
try {
String line = br.readLine();
while (line != null) {
if(!Character.isDigit(line.charAt(0)) {
// there is a problem if your artist name starts with a "0" so add some more checks here
token = line.split(" : ");
artistName = token[0];
albumTitle = token[1];
if(!tracks.isEmpty()) {
album = new Album(artistName,albumTitle,tracks);
albumCollection.add(album);
tracks.clear();
}
}
else {
tracks.add(new Track(line))
}
line = br.readLine();
}
} finally {
br.close();
}
You said you want to print all tracks?!
for(Album alb : albumCollection) {
// I dont know about your implementation of the Album class but I assume:
System.out.println(alb.getTitle());
System.out.println("##TRACKS###");
ArrayList<Track> trs = alb.getTracks();
for(Track tr : trs) {
String trackName = tr.getTitle(); // I assume again..
System.out.println(trackName);
// .....
}
}
Related
My code below
import java.util.*;
import java.io.*;
public class main {
public int finalcost;
public static void main(String[] args) throws FileNotFoundException, IOException {
Scanner input = new Scanner(System.in);
int totalAdd = 0;
boolean done = false;
// to store specific properties ex item size and price
HashMap<String, String> specificPropsMap = new HashMap<String, String>();
// stores an array list of all the sizes and price
ArrayList<HashMap<String, String>> propsList = new ArrayList<HashMap<String, String>>();
// the item list stores the name of the item as the KEY and item size and price
// as data
HashMap<String, ArrayList<HashMap<String, String>>> itemsMap = new HashMap<String, ArrayList<HashMap<String, String>>>();
// this stores the service name than the cost.this is the one we will be adding
// too after getting the data;
HashMap<String, Integer> cartMap = new HashMap<String, Integer>();
BufferedReader br = new BufferedReader(new FileReader("PA2.txt"));
String line = br.readLine();
while ((line = br.readLine()) != null) {
// stores the data base on commas
String[] fields = line.split(",");
String serviceName = fields[0];
String fileName = fields[1];
String cost = fields[2];
if (specificPropsMap.containsKey(serviceName)) {
// do nothing
} else {
specificPropsMap.put(serviceName, null);
}
// gets the file name from the first reader
BufferedReader brCVS = new BufferedReader(new FileReader(fileName));
String lineCVS = brCVS.readLine();
while ((lineCVS = brCVS.readLine()) != null) {
String[] cvsFields = lineCVS.split(",");
String brandName = cvsFields[0];
String nameItem = cvsFields[1];
String itemSize = cvsFields[2];
String itemPrice = cvsFields[3];
// check if itemname is in specificPropsMap
if (specificPropsMap.containsKey(cvsFields[1])) {
// do nothing
} else {
specificPropsMap.put(itemSize, nameItem);
}
propsList.add(specificPropsMap);
if (itemsMap.containsKey(nameItem)) {
// do nothing
} else {
itemsMap.put(nameItem, null);
}
} // end inner while loop
int stringCosttoInt = Integer.parseInt(cost.trim());
if (cartMap.containsKey(serviceName)) {
// do nothing
} else {
cartMap.put(serviceName, stringCosttoInt);
}
} // end outer while loop
System.out.println("Welcome to Assisgnment two app");
while (done == false) {
System.out.println("Enter the item you are looking for or enter done check out: ");
String key = input.nextLine(); // use key to find if item is in the itemsMap;
if (key == "done") {
done = true;
} else {
if (itemsMap.containsKey(key)) {
System.out.println("Enter the Size you want :");
// now check for the item name, than size, if not return item not there;
int sizeKey = input.nextInt(); // use key to find item in the area
if (itemsMap.containsValue(specificPropsMap.containsKey(sizeKey))) {
System.out.println("How many of " + key + " do you want:");
int numOfProduct = input.nextInt();
// add it to the cart;
} else {
System.out.println("No: " + sizeKey + " in the system");
}
} else {
System.out.println("No item by the name of: " + key + " in the system");
}
}
}
br.close();
input.close();
}
}
Question: How do I set the user input to search the item class to return the lowest total cost. The user enters item name, size and the amount. I know in storing the name in item, but I don't know how to match it with user input or how to get that data if that makes sense.2nd in also little confused when I read the file and i'm storing it as a String, I don't know how to make it into an int so I can do math with it..
Just to give you some help with the approach, I won't be going into detail about parsing, I think you got that covered.
Look at it from another perspective, from the input. What is the flow of the program?
User enters required item and size
Look if item is present
User enters quantity
Add to cart
Repeat
When 'done', check which Service offers lowest total price
Note: Assuming an item present in one Brand is present in all
So let's devise a Data Structure that can support this:
We need to maintain a Cart for each Service. In the end, we can cycle through each cart and return the lowest.
Maintain a Map<String, Integer> where String is the Service, and Integer is the total price
Whenever an Item is added by the user, add the price of that Item to each respective Service
Eg. If Lays is added, add price of Lays in Prime to total price of Prime, price of Lays in InstaCart to total price of InstaCart, etc
First thing you need to look up is if the Item is present; we can store it in a Map, say itemsMap.
What specific properties does each item have? There's service, brand, size, price. We can store it in another Map, say specificPropsMap.
Each Item can have multiple specific properties. i.e., There can be different combination of size, service, etc. for the same Item. So each Item needs to store multiple specific properties, which can be a List, say propsList.
To understand the above:
//Starting from the bottom-up
//To store specific properties
//Contains key-value pairs like: service = Amazon, brand = Nestle, size = 10g, price = 2
HashMap<String, String> specificPropsMap; //Has one set of specific props
//Consider an Item; it can have multiple specific properties, which we'll store as a List
//Eg: For Item = 'dark chocolate'
//specificProps1: service = Amazon, brand = Nestle, size = 10, price = 2
//specificProps1: service = InstaCart, brand = Cadbury, size = 10, price = 3
//Required: List<specificPropsMap>
ArrayList<HashMap<String, String>> propsList; //Has a list of specificPropsMaps for one item
//Now we need to store all Items; it can be a Map
//Required: Map<ItemName, propsList for that Item>
HashMap<String, ArrayList<HashMap<String, String>>> itemsMap;
//Initialize cart Map while parsing services
HashMap<String, Integer> cartMap; //Has initial values "Amazon" = 0, InstaCart = 0
//To find if an Item is present:
itemsMap.contains("Dark chocolate");
//Find prices from each service for that Item and size, and quantity
int reqSize = 10; //Assume req. size = 10
int reqQuantity = 5;
ArrayList<HashMap<String, String>> propsList = itemsMap.get("Dark chocolate")
for (HashMap<String, String> specificPropsMap : propsList) { //For each set of props
int size = Integer.parseInt(specificPropsMap.get("size"));
if (size == reqSize) {
String service = specificPropsMap.get("service"); //Say Amazon
int price = Integer.parseInt(specificPropsMap.get("price")); //Say 2
int initialPriceInCart = cartMap.get(service); //Initially 0
int finalPriceInCart = initialPriceInCart + price * reqQuantity;
cartMap.put(service, finalPriceInCart); //Cart price updated
}
}
//Find lowest priced service
String lowestPrice = Integer.MAX_VALUE; //Initially set as high as possible
String lowestService = "";
for (String key : cartMap.keySet()) {
if (cartMap.get(key) < lowestPrice) {
lowestPrice = cartMap.get(key);
lowestService = key;
}
}
General pointers that I can think of:
Population: Populate all these values initially while reading from the files.
Conversion : Convert values such as size, price to a standard (kg, cents/dollars, etc)
Naming : It's better to keep it descriptive (brand or brandName instead of bName)
Error handling : Add checks/try-catch blocks wherever necessary
Edit: Added steps. Might look a bit complex since we have some entries in the txt and some in the csv, but it's actually easy:
Read txt file; you now have a service and a csv file. Thus, for each service(outer loop)
Add the service as a key to cartMap if it's not already present
Create a new specificPropsMap, add service to this
Read the csv corresponding to that service. For each item(inner loop)
Store all props in the same specificPropsMap
You now have the prop item from the csv
Check if item is present in itemsMap
If present, skip to next step. If not, add item to the itemsMap as a key, with an empty List as value
Do itemsMap.get(item), you'll have the propsList
Add specificPropsMap to the propsList
Repeat for all items and all services.
I have three input fields.
First Name
Last item
Date Of Birth
I would like to get random data for each input from a property file.
This is how the property file looks. Field name and = should be ignored.
- First Name= Robert, Brian, Shawn, Bay, John, Paul
- Last Name= Jerry, Adam ,Lu , Eric
- Date of Birth= 01/12/12,12/10/12,1/2/17
Example: For First Name: File should randomly select one name from the following names
Robert, Brian, Shawn, Bay, John, Paul
Also I need to ignore anything before =
FileInputStream objfile = new FileInputStream(System.getProperty("user.dir "+path);
in = new BufferedReader(new InputStreamReader(objfile ));
String line = in.readLine();
while (line != null && !line.trim().isEmpty()) {
String eachRecord[]=line.trim().split(",");
Random rand = new Random();
//I need to pick first name randomly from the file from row 1.
send(firstName,(eachRecord[0]));
If you know that you're always going to have just those 3 lines in your property file I would get put each into a map with an index as the key then randomly generate a key in the range of the map.
// your code here to read the file in
HashMap<String, String> firstNameMap = new HashMap<String, String>();
HashMap<String, String> lastNameMap = new HashMap<String, String>();
HashMap<String, String> dobMap = new HashMap<String, String>();
String line;
while (line = in.readLine() != null) {
String[] parts = line.split("=");
if(parts[0].equals("First Name")) {
String[] values = lineParts[1].split(",");
for (int i = 0; i < values.length; ++i) {
firstNameMap.put(i, values[i]);
}
}
else if(parts[0].equals("Last Name")) {
// do the same as FN but for lastnamemap
}
else if(parts[0].equals("Date of Birth") {
// do the same as FN but for dobmap
}
}
// Now you can use the length of the map and a random number to get a value
// first name for instance:
int randomNum = ThreadLocalRandom.current().nextInt(0, firstNameMap.size(0 + 1);
System.out.println("First Name: " + firstNameMap.get(randomNum));
// and you would do the same for the other fields
The code can easily be refactored with some helper methods to make it cleaner, we'll leave that as a HW assignment :)
This way you have a cache of all your values that you can call at anytime and get a random value. I realize this isn't the most optimum solution having nested loops and 3 different maps but if your input file only contains 3 lines and you're not expecting to have millions of inputs it should be just fine.
Haven't programmed stuff like this in a long time.
Feel free to test it, and let me know if it works.
The result of this code should be a HashMap object called values
You can then get the specific fields you want from it, using get(field_name)
For example - values.get("First Name"). Make sure to use to correct case, because "first name" won't work.
If you want it all to be lower case, you can just add .toLowerCase() at the end of the line that puts the field and value into the HashMap
import java.lang.Math;
import java.util.HashMap;
public class Test
{
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
// set the value of "in" here, so you actually read from it
HashMap<String, String> values = new HashMap<String, String>();
String line;
while (((line = in.readLine()) != null) && !line.trim().isEmpty()) {
if(!line.contains("=")) {
continue;
}
String[] lineParts = line.split("=");
String[] eachRecord = lineParts[1].split(",");
System.out.println("adding value of field type = " + lineParts[0].trim());
// now add the mapping to the values HashMap - values[field_name] = random_field_value
values.put(lineParts[0].trim(), eachRecord[(int) (Math.random() * eachRecord.length)].trim());
}
System.out.println("First Name = " + values.get("First Name"));
System.out.println("Last Name = " + values.get("Last Name"));
System.out.println("Date of Birth = " + values.get("Date of Birth"));
}
}
I am trying to read a file of string int and boolean values into an array list as object blocks. The string values go into the array list just fine, its the boolean values I'm having trouble with. Every time I encounter the variable 'active'there is a mismatch exception. Please help! The text file for if the block is a wizard goes in this order
name (string)
location (string)
active (boolean) ... the one I'm having issues with
skill level (int)
friendliness (int)
I included the driver class as well as the Witch class which contains the
variable 'active' originally.
Driver class that adds objects to the array list based on what the scanner
reads from the file
package project2;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
public class Project2 {
public static void main(String[] args) {
Scanner inputFileScanner1 = null;
//file name
String listFile = "list.txt";
// Check to see if file exists
try {
inputFileScanner1 = new Scanner(new File(listFile));
} catch (FileNotFoundException e) {
System.out.println("Error opening file.");
System.exit(1);
}
//create Individuals arraylist and Location arraylist
ArrayList < Individual > Individual = new ArrayList < > ();
ArrayList < String > Location = new ArrayList < > ();
//declare variables to read file contents into the arraylist
String wizName, witchName, individualName, location, position,
profession = null, line = null;
int wizLevel, witchSkillLevel, friendliness;
boolean active;
//while there is a next line, if the line equals Wizard, the next four lines
// are wizard name, location, position and level
while (inputFileScanner1.hasNext()) {
line = inputFileScanner1.nextLine();
if (line.trim().equals("Wizard")) {
wizName = inputFileScanner1.nextLine().trim();
location = inputFileScanner1.nextLine().trim();
position = inputFileScanner1.nextLine().trim();
wizLevel = inputFileScanner1.nextInt();
//create wizard object
Individual wizard = new Wizard(wizName, location, position, profession, wizLevel);
//fill arraylist with wizard objects
Individual.add(wizard);
Location.add(location);
} //if the next line is Witch, the next five lines are
// witch name, location, yes/no active, skill level, and friendliness
//in that order
else if (line.trim().equals("Witch")) {
witchName = inputFileScanner1.nextLine().trim();
location = inputFileScanner1.nextLine().trim();
active = inputFileScanner1.nextBoolean();
witchSkillLevel = inputFileScanner1.nextInt();
friendliness = inputFileScanner1.nextInt();
//create witch object
Individual witch = new Witch(witchName, location, profession, witchSkillLevel, friendliness, active);
//fill the arraylist with witch objects
Individual.add(witch);
Location.add(location);
} else {
profession = line.trim();
individualName = inputFileScanner1.nextLine().trim();
location = inputFileScanner1.nextLine().trim();
Individual i = new Individual(profession, individualName, location);
Individual.add(i);
Location.add(location);
}
java.util.Collections.sort(Individual);
java.util.Collections.sort(Location);
}
System.out.println("List of friends and possible allies: " + Location);
inputFileScanner1.close();
}
}
//Witch class which holds values that are in the text file. active is the boolean value Im having trouble with
package project2;
public class Witch extends Individual implements Magical {
private int skill;
private int friendly;
//Constructor with witch parameters
public Witch(String name, String location, String profession,
int skill, int friendly, boolean active) {
}
//default constructor
public Witch() {
this("", "", "", 0, 0, false);
}
//overridden abstract method from magical interface
#Override
public void assess() {
System.out.print(this.friendly + " " + this.skill + " " + super.toString());
}
}
<!-- end snippet -->
Text file :
enter image description here
When you pull in your boolean variable do something like this.
if(inputFileScanner1.nextLine().trim().equals("yes"))
{
active = true;
}
else
{
active = false;
}
Okay, the problem is that the file contains the strings yes and no, that are not directly parsable as booleans (should be true or false).
If you can change the original data file somehow, I would suggest to use the two true and false keywords, otherwise, the #Sendrick Jefferson solution will do the job (at your own risk: every typo, as for instance "ye", will be translated into false).
What I want to do is read a text file that has humans and animals. It will compile but has an error when I try to run it. I think I need a for loop to read the stringtokenizer to decipher between the human and animal in the txt file so far this is my driver class.
txt file:
Morely,Robert,123 Anywhere Street,15396,4,234.56,2
Bubba,Bulldog,58,4-15-2010,6-14-2011
Lucy,Bulldog,49,4-15-2010,6-14-2011
Wilder,John,457 Somewhere Road,78214,3,124.53,1
Ralph,Cat,12,01-16-2011,04-21-2012
Miller,John,639 Green Glenn Drive,96258,5,0.00,3
Major,Lab,105,07-10-2012,06-13-2013
King,Collie,58,06-14-2012,10-05-2012
Pippy,cat,10,04-25-2015,04-25-2015
Jones,Sam,34 Franklin Apt B,47196,1,32.09,1
Gunther,Swiss Mountain Dog,125,10-10-2013,10-10-2013
Smith,Jack,935 Garrison Blvd,67125,4,364.00,4
Perry,Parrot,5,NA,3-13-2014
Jake,German Shepherd,86,11-14-2013,11-14-2013
Sweetie,tabby cat,15,12-15-2013,2-15-2015
Pete,boa,8,NA,3-15-2015
Source:
import java.util.Scanner;
import java.util.StringTokenizer;
import java.io.File;
import java.io.IOException;
/**
* This is my driver class that reads from a txt file to put into an array and uses the class refrences so it can use the menu and spit out
*
* #author ******
* #version 11/25/2015
*/
public class Driver
{
/**
* Constructor for objects of class Driver, what it does is read in the txt file gets the two class refrences and loops through to read through the whole file looking for string tokens to go to the next line
* and closes the file at the end also uses for loop to count number of string tokens to decipher between human and pets.
*/
public static void main(String[] args) throws IOException
{
Pet p;
Human h;
Scanner input;
char menu;
input = new Scanner(new File("clientdata.txt"));
int nBalance;
int id;
/**
* this while statement goes through each line looking for the string tokenizer ",". I want to count each "," to decipher between Human and Animal
*/
while(input.hasNext())
{
StringTokenizer st = new StringTokenizer(input.nextLine(), ",");
h = new Human();
h.setLastName(st.nextToken());
h.setFirstName(st.nextToken());
h.setAddress(st.nextToken());
h.setCiD(Integer.parseInt(st.nextToken()));
h.setVisits(Integer.parseInt(st.nextToken()));
h.setBalance(Double.parseDouble(st.nextToken()));
p = new Pet(st.nextToken(), st.nextToken(), Integer.parseInt(st.nextToken()), st.nextToken(), st.nextToken());
}
/**
* this is my seond while statement that loops the case switch statements and asks the user for client ID
*/
menu = 'Y';
while(menu == 'y' || menu == 'Y') {
System.out.print("\nChose one:\n A- client names and outstanding balance \n B- client's pets, name, type and date of last visit\n C-change the client's outstanding balance: ");
menu = input.next().charAt(0);
System.out.print("Enter client ID: ");
id = input.nextInt();
h = new Human();
if(id == h.getCiD())//if the id entered up top is equal to one of the id's in the txt file then it continues to the menu
{
p = new Pet();
switch(menu)
{ case 'A':
System.out.println("client name: " + h.getFirstName() + "outstanding balance: " + h.getBalance());
break;
case 'B':
System.out.println("pet's name: " + p.getName() + "type of pet: " + p.getTanimal() + "date of last visit: " + p.getLastVisit());
break;
case 'C':
System.out.println("what do you want to change the clients balances to?");
input.close();
}
}
else// if not then it goes to this If statement saying that the Client does not exist
{
System.out.println("Client does not exist.");
}
}
}
}
You have a number of issues you need to overcome...
For each line, you need to determine the type of data the line represents
You need some way to keep track of the data you've loaded (of the clients and their pets)
You need some way to associate each pet with it's owner
The first could be done in a number of ways, assuming we can change the data. You could make the first token meaningful (human, pet); you could use JSON or XML instead. But lets assume for the moment, you can't change the format.
The key difference between the two types of data is the number of tokens they contain, 7 for people, 5 for pets.
while (input.hasNext()) {
String text = input.nextLine();
String[] parts = text.split(",");
if (parts.length == 7) {
// Parse owner
} else if (parts.length == 5) {
// Parse pet
} // else invalid data
For the second problem you could use arrays, but you would need to know in advance the number of elements you will need, the number of people and for each person, the number of pets
Oddly enough, I just noticed that the last element is an int and seems to represent the number of pets!!
Morely,Robert,123 Anywhere Street,15396,4,234.56,2
------------^
But that doesn't help us for the owners.
For the owners, you could use a List of some kind and when ever you create a new Human, you would simply add them to the List, for example...
List<Human> humans = new ArrayList<>(25);
//...
if (parts.length == 7) {
// Parse the properties
human = new Human(...);
humans.add(human);
} else if (parts.length == 5) {
Thirdly, for the pets, each Pet should associated directly with the owner, for example:
Human human = null;
while (input.hasNext()) {
String text = input.nextLine();
String[] parts = text.split(",");
if (parts.length == 7) {
//...
} else if (parts.length == 5) {
if (human != null) {
// Parse pet properties
Pet pet = new Pet(name, type, age, date1, date2);
human.add(pet);
} else {
throw new NullPointerException("Found pet without human");
}
}
Okay, so all this does, is each time we create a Human, we keep a reference to the "current" or "last" owner created. For each "pet" line we parse, we add it to the owner.
Now, the Human class could use either a array or List to manage the pets, either will work, as we know the expected number of pets. You would then provide getters in the Human class to get a reference to the pets.
Because out-of-context code can be hard to read, this is an example of what you might be able to do...
Scanner input = new Scanner(new File("data.txt"));
List<Human> humans = new ArrayList<>(25);
Human human = null;
while (input.hasNext()) {
String text = input.nextLine();
String[] parts = text.split(",");
if (parts.length == 7) {
String firstName = parts[0];
String lastName = parts[1];
String address = parts[2];
int cid = Integer.parseInt(parts[3]);
int vists = Integer.parseInt(parts[4]);
double balance = Double.parseDouble(parts[5]);
int other = Integer.parseInt(parts[6]);
human = new Human(firstName, lastName, address, cid, vists, balance, other);
humans.add(human);
} else if (parts.length == 5) {
if (human != null) {
String name = parts[0];
String type = parts[1];
int age = Integer.parseInt(parts[2]);
String date1 = parts[3];
String date2 = parts[4];
Pet pet = new Pet(name, type, age, date1, date2);
human.add(pet);
} else {
throw new NullPointerException("Found pet without human");
}
}
}
What about using split() function instead of using StringTokenizer?
Say, You can change your first while loop like below:
while (input.hasNext()) {
// StringTokenizer st = new StringTokenizer(input.nextLine(), ",");
String[] tokens = input.nextLine().split(",");
if (tokens.length == 7) {
h = new Human();
h.setLastName(tokens[0]);
h.setFirstName(tokens[1]);
h.setAddress(tokens[2]);
h.setCiD(Integer.parseInt(tokens[3]));
h.setVisits(Integer.parseInt(tokens[4]));
h.setBalance(Double.parseDouble(tokens[5]));
} else {
p = new Pet(tokens[0], tokens[1], Integer.parseInt(tokens[2]), tokens[3], tokens[4]);
}
}
And for keeping track of which pet belongs to which human, you can append an arrayList of type Pet in Human class like below:
ArrayList<Pet> pets = new ArrayList<>();
And say you have another ArrayList of type Human named humans in the main function. So, you could append in if block like:
humans.add(h);
and in the else section, you could append in else block:
humans.get(humans.size()-1).pets.add(p);
You can try something like this -
Populate a map and then using that you can assign values according to your requirement.
public void differentiate(){
try {
Scanner scan=new Scanner(new BufferedReader(new FileReader("//your filepath")));
Map<String,List<String>> map=new HashMap<String, List<String>>();
while(scan.hasNextLine()){
List<String> petList=new ArrayList<String>();
String s=scan.nextLine();
String str[]=s.split(",");
String name=str[1]+" "+str[0];
int petCount=Integer.parseInt(str[str.length-1]);
for(int i=1;i<=petCount;i++){
String petString=scan.nextLine();
petList.add(petString);
}
map.put(name, petList);
}
Set<String> set=map.keySet();
for(String str:set){
System.out.println(str+" has "+map.get(str)+" pets");
}
}
catch (FileNotFoundException e) {
System.out.println(e.getMessage());
}
}
I have a class called CD with the following private variables:
private String artist = "";
private String year = "";
private String albumName = "";
private ArrayList<String> songs = new ArrayList<String>();
This class is used to store input data that is in this format:
Led Zeppelin
1979 In Through the Outdoor
-In the Evening
-South Bound Saurez
-Fool in the Rain
-Hot Dog
-Carouselambra
-All My Love
-I'm Gonna Crawl
I have a CDParser class that is in charge of parsing the file called sample.db line by line to store it into our CD object. After parsing, the CD object, after initializing it with CD newCD = new CD() has the following structure:
artist = "Led Zeppelin"
year = "1979"
albumName = "In Through the Outdoor"
songs = {"-In the Evening", "-South Bound Saurez", "-Fool in the Rain", "-Hot Dog"}
Now.. For this project, sample.db contains many albums, which looks like the following:
Led Zeppelin
1979 In Through the Outdoor
-In the Evening
-South Bound Saurez
-Fool in the Rain
-Hot Dog
-Carouselambra
-All My Love
-I'm Gonna Crawl
Led Zeppelin
1969 II
-Whole Lotta Love
-What Is and What Should Never Be
-The Lemon Song
-Thank You
-Heartbreaker
-Living Loving Maid (She's Just a Woman)
-Ramble On
-Moby Dick
-Bring It on Home
Bob Dylan
1966 Blonde on Blonde
-Rainy Day Women #12 & 35
-Pledging My Time
-Visions of Johanna
-One of Us Must Know (Sooner or Later)
-I Want You
-Stuck Inside of Mobile with the Memphis Blues Again
-Leopard-Skin Pill-Box Hat
-Just Like a Woman
-Most Likely You Go Your Way (And I'll Go Mine)
-Temporary Like Achilles
-Absolutely Sweet Marie
-4th Time Around
-Obviously 5 Believers
-Sad Eyed Lady of the Lowlands
I have so far been able to parse all three different albums and save them into my CD object, but ran into a roadblock where I'm simply saving all three albums into the same newCD object.
My question is - is there a way of programmatically initialize my CD constructor that will follow the format newCD1, newCD2, newCD3, etc, as I parse the sample.db?
What this means is, as I parse this particular file:
newCD1 would be the album In Through the Outdoor (and its respective private vars)
newCD2 would be the album II (and its respective private vars)
newCD3 would be the album Blonde on Blonde, and so on
Is this a smart way to do it? Or could you suggest me a better way?
EDIT:
Attached is my parser code. ourDB is an ArrayList containing every line of sample.db:
CD newCD = new CD();
int line = 0;
for(String string : this.ourDB) {
if(line == ARTIST) {
newCD.setArtist(string);
System.out.println(string);
line++;
} else if(line == YEAR_AND_ALBUM_NAME){
String[] elements = string.split(" ");
String[] albumNameArr = Arrays.copyOfRange(elements, 1, elements.length);
String year = elements[0];
String albumName = join(albumNameArr, " ");
newCD.setYear(year);
newCD.setAlbumName(albumName);
System.out.println(year);
System.out.println(albumName);
line++;
} else if(line >= SONGS && !string.equals("")) {
newCD.setSong(string);
System.out.println(string);
line++;
} else if(string.isEmpty()){
line = 0;
}
}
You have a single CD object, so you keep overwriting it. Instead, You could hold a collection of CDs. E.g.:
List<CD> cds = new ArrayList<>();
CD newCD = new CD();
int line = 0;
for(String string : this.ourDB) {
if(line == ARTIST) {
newCD.setArtist(string);
System.out.println(string);
line++;
} else if(line == YEAR_AND_ALBUM_NAME){
String[] elements = string.split(" ");
String[] albumNameArr = Arrays.copyOfRange(elements, 1, elements.length);
String year = elements[0];
String albumName = join(albumNameArr, " ");
newCD.setYear(year);
newCD.setAlbumName(albumName);
System.out.println(year);
System.out.println(albumName);
line++;
} else if(line >= SONGS && !string.equals("")) {
newCD.setSong(string);
System.out.println(string);
line++;
} else if(string.isEmpty()){
// We're starting a new CD!
// Add the one we have so far to the list, and start afresh
cds.add(newCD);
newCD = new CD();
line = 0;
}
}
// Take care of the case the file doesn't end with a newline:
if (line != 0) {
cds.add(newCD);
}
The problem is that you're using the same object reference of CD to fill the values of the parse of the file.
Just make sure to initialize and store every instance of CD newCD every time you start parsing the content of a new album.
You may do the following:
List<CD> cdList = new ArrayList<>();
for (<some way to handle you're reading a new album entry from your file>) {
CD cd = new CD();
//method below parses the data in the db per album entry
//an album entry may contain several lines
parseData(cd, this.ourDB);
cdList.add(cd);
}
System.out.println(cdList);
Your current way to parse the file works but is not as readable as it should be. I would recommend using two loops:
List<CD> cdList = new ArrayList<>();
Iterator<String> yourDBIterator = this.ourDB.iterator();
//it will force to enter the first time
while (yourDBIterator.hasNext()) {
//do the parsing here...
CD cd = new CD();
//method below parses the data in the db per album entry
//an album entry may contain several lines
parseData(cd, yourDBIterator);
cdList.add(cd);
}
//...
public void parseData(CD cd, Iterator<String> it) {
String string = it.next();
int line = ARTIST;
while (!"".equals(string)) {
if (line == ARTIST) {
newCD.setArtist(string);
System.out.println(string);
line++;
} else if(line == YEAR_AND_ALBUM_NAME){
String[] elements = string.split(" ");
String[] albumNameArr = Arrays.copyOfRange(elements, 1, elements.length);
String year = elements[0];
String albumName = join(albumNameArr, " ");
newCD.setYear(year);
newCD.setAlbumName(albumName);
System.out.println(year);
System.out.println(albumName);
line++;
} else if(line >= SONGS && !string.equals("")) {
newCD.setSong(string);
System.out.println(string);
line++;
}
if (it.hasNext()) {
string = it.next();
} else {
string = "";
}
}
}
Then, your code
I suggest to use the Builder design pattern to construct the CD object. If you read lines always in the same order, it will be not complicated to implement and use. Good tutorial: http://www.javacodegeeks.com/2013/01/the-builder-pattern-in-practice.html