How to parse String and send multiple values to constructor - java

I am doing a class assignment where I have to parse a given string into different types of variables. The different variables are: Name, Surname, Date of Birth, City of Birth. After this is done, the variables needs to be sent to the constructor of the class Person.
I am stuck with how to assign the three different values to a variable and then send it back to the constructor. I have tried declaring an array for each variable and then filling it with for loop with the values but then I ran into trouble finding a neat way of declaring its length plus I think I would need to convert the array back to strings in order to pass the values to the constructor and the resulting code would be messy. Is there a simpler way of doing this?
I don't know if this will change anything in the code but after I passed the values to the constructor, I need to send that object to a List collection and use it to print the details about each person.
Here is my current code:
public static void main(String[] args) {
// Given string to parse
String text = "John.Davidson/05051988/Belgrade Michael.Barton/01011968/Krakov Ivan.Perkinson/23051986/Moscow";
String[] parsArray = text.split("[ /.]+");
// Results from parsing
for (Object s: parsArray)
{
System.out.println(s);
}
for (int i = 0; i<parsArray.length; i+=4)
{
String firstName = parsArray[i];
String lastName = parsArray[i+1];
String birthPlace = parsArray[i+3];
System.out.println("\nFirst name: " + firstName + "\nLast name: " + lastName + "\nCity of birth: " + birthPlace);
}
}
}
Class Person and its constructor:
import java.time.LocalDate;
public class Person {
String name;
String surname;
LocalDate dob;
String placeOfBirth;
public Person(String name, String surname, LocalDate dob, String placeOfBirth)
{
this.name = name;
this.surname = surname;
this.dob = dob;
this.placeOfBirth = placeOfBirth;
}
}

Use an ArrayList to store the Person objects
DateTimeFormatter dobFormatter = DateTimeFormatter.ofPattern("ddMMuuuu");
ArrayList<Person> list = new ArrayList <Person> ();
for (int i = 0; i<parsArray.length; i+=4)
{
String firstName = parsArray[i];
String lastName = parsArray[i+1];
LocalDate dob = LocalDate.parse(parsArray[i+2], dobFormatter);
String birthPlace = parsArray[i+3];
System.out.println("\nFirst name: " + firstName + "\nLast name: " + lastName + "\nCity of birth: " + birthPlace);
list.add (new Person (firstName, lastname, dob, birthPlace));
}

You are on the right track, but I think you'll make some additional headway if you can structure your code in a way that helps you isolate problems. The goal is to break the problem into small enough pieces to tackle in simple, cohesive functions. I like to sketch out classes or methods before trying to fill in their details. But first, I start by talking my way through the problem.
The goal is to convert a single line of text into a collection of type-specific Person objects. The input uses a single space a record delimiter, '.' periods to separate the first name from the surname, and '/' slashes to separate the other fields within the record. Ahhh ... a classic.
The first step is to merely isolate the blocks of text that deal with each individual record. I can see that because the first thing I noticed about the input text was that it used spaces to separate information about different persons. No need to try to write code that tries to swallow the whale in one bite, right?
String[] parseRecords(String input) {
return input.split("[ ]+");
}
Now that records are isolated from one another, we need a method to produce a Person record from a block of text that only contains a single record i.e. a subset of the original input that only contains information about a single person. In my problem description, I noticed that both '.' and '/' are used as field delimiters so we can separate into fields on either. There are many other ways to write this regular expression but I've copied your approach used in the question.
Person parsePersonFromString(String text) {
String[] fields = text.split("[./]+");
LocalDate dob = /* something with field[2] */
return new Person(fields[0], fields[1], dob, fields[3]);
}
Notice the split array of Strings should have length 4. The first two fields are names so they already in a String type. Same goes for the city field. The date field gets a bit trickier because you have a String and you want a LocalDate. Since this is homework I'll leave the details to you, but keep in mind if you run into trouble this too is something you could break down into a simpler problem!
LocalDate parseDateFromField(String field) {
}

Related

How to add different data types from text file into an arraylist?

I'm currently reading up java's IO chapter regarding files and got me wondering what if,
there are different data types in a text file, for example:
Position(in type String), ID(in type long), Name(in type String), Birthdate(dd/mm/yy in 3 type ints), title(Ms/Mr/Dr in type String), tasks done(in type int):
file name: employeeInfo.txt
Manager, 987298347, Tesla, 03,04,1969, Mr, 4
Assistant, 290375020, Chris, 17,11,1989, Mr, 5
Manager, 99832482322, Steph, 11,02,1980, Ms, 4
Assistant, 679730283, Pete, 09,10,1980, Mr,7
How do I store them into two ArrayList that are grouped according to their position, in code? In order for me to do any flexible tasks, for example:
1. able to find out which employee achieve task done with more than 3
2. display employee's info when its ID is entered
Then the result may be as follows if 2 is invoked:
input:
290375020
output:
Assistant, 290375020, Chris, 17/11/1989, Mr, 5
I hope there isn't any confusion caused.
Thank you in advance
I think it would be nice to create a class representing the data on a single line, parse each line into an instance of your class, and then compare the objects1.
Something like this:
List<Person> persons = new ArrayList<>();
for (String line : lines) { // Read the lines somehow
String[] parts = line.split(", ");
String position = parts[0];
long id = Long.parseLong(parts[0]);
// Et cetera
persons.add(new Person(position, id, ...);
}
Then you can easily get all persons with tasks >= 3 in a for loop for example.
for (Person person : persons) {
if (person.getTasks() >= 3) {
// Print out the person
}
}
By the way, a birthdate is best represented by a LocalDate. You can parse the date with
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd,MM,yyyy");
LocalDate dob = LocalDate.parse(parts[3], formatter);
Grouping
Grouping is often done using a Map. You could map each employee position to a list containing the employees with that position:
List<Person> personsFromFile = ...;
Map<String, List<Person>> map = new HashMap<>();
for (Person person : personsFromFile) {
// If the position does not yet exist as key in the map, create it
if (!map.containsKey(person.getPosition())) {
map.put(person.getPosition(), new ArrayList<>());
}
// Get the list with for this position and add the current person to it
map.get(person.getPosision()).add(person);
}
Or using Java Streams API:
personsFromFile.stream()
.collect(Collectors.groupingBy(p -> p.getPosision()));
1 This is the whole point of object-oriented programming. We don't work with a bunch of variables, we model related data and functional classes and define functions operate on that object. Those are called methods. Each line in your file represents a person (or employee, you name it), so create a Person (or Employee) class.
Think in rows (objects) rather than columns
Java is object-oriented, so use objects. Rather than track each column of data in your data file, write a class to represent each kind of data found in a row. Each value in the row goes into a named member field on the class.
As your read each row, instantiate an object of that class, and populate its values. Add each new object to a List as you work your way brought the input file.
Tip: In real work, use a CSV library to help with reading and parsing such a comma-separated values file. You have a choice of such libraries in Java. Personally, I use Apache Commons CSV.
For the employee class
class employee {
private String position;
private long ID;
private String Name;
private String dob;
private String title;
private int task_done;
public employee(String position, long ID, String Name, String dob, String title, int task_done) {
this.position = position;
this.ID = ID;
this.Name = Name;
this.dob = dob;
this.title = title;
this.task_done = task_done;
}
public long getID(){
return ID;
}
public int getTask() {
return task_done;
}
}
Main
public static void main(String[] args) throws IOException {
List<employee> employees = new ArrayList<employee>();
BufferedReader inFile = new BufferedReader(new FileReader("Filepath.txt"));
String inputline;
while ((inputline = inFile.readLine()) != null) {
String[] data = inputline.split(", ");
employees.add(new employee(data[0], Long.parseLong(data[1]), data[2], data[3], data[4], Integer.parseInt(data[5])));
}
inFile.close();
for (employee em : employees) {
if (em.getTask() >= 3) {
System.out.println(em.getID());
}
}
}
The file: (I have remove the commas for the Birthdate)
Manager, 987298347, Tesla, 03/04/1969, Mr, 4
Assistant, 290375020, Chris, 17/11/1989, Mr, 5
Manager, 99832482322, Steph, 11/02/1980, Ms, 4
Assistant, 679730283, Pete, 09/10/1980, Mr, 7
The output:
987298347
290375020
99832482322
679730283
You can modify it to do flexible tasks.

Using an array to store multiple variables from user input

I am relatively new to Java and would like to know how to store variables separately from a single line of user input.
At the minute the user is prompted to enter football results in the following format
home_name : away_name : home_score : away_score
and I am using a while loop to continue to ask user for input until they enter "stop"
(while (input != "stop))
Once the loop is broken I would like my program to output a variety of data such as total games played, but I'm struggling to store the home_name, away_name etc.. especially if the user wishes to enter multiple lines of results.
Two mainstream ways to store a "record" are:
Maps
Data objects
A map is more generic:
Map<String,String> match = new HashMap<>();
match.put("home_name", "Alvechurch Villa");
match.put("away_name", "Leamington");
match.put("home_score", "0");
match.put("away_score", "6");
You can add a map to a list:
List<Map<String,String>> matches = new ArrayList<>();
matches.add(list);
... and retrieve them:
Map<String,String> match = matches.get(0);
System.out.println(match.get("away_score"));
A data object is more tuned to your data format, but you have to write the class yourself.
public class Match {
public String homeName;
public String awayName;
public int homeScore;
public int awayScore;
}
Now you can use this class:
Match match = new Match();
match.homeName = "Studley";
// etc.
You can add and retrieve these from lists too:
List<Match> matches = new ArrayList<>();
matches.add(match);
Match aMatch = matches.get(0);
This is simple, but it's considered bad practice to have public fields like this - it's better to get at them via methods. For brevity, here's a data class with only one field:
public class Player {
private String name;
public Player(String name) {
this.name = name;
}
public String name() {
return name;
}
}
Player neilStacey = new Player("Neil Stacey");
You can use the same technique with all the fields in Match.
(A common style is to name a method like this getName(), and also to have a setName(). I have used a different style and made the object immutable, in an effort to set a good example!)
One advantage of the data object is that it has different types for different fields: homeName is a String, homeScore is an integer. All the fields in the Map are Strings. You can get around this by using Map<String,Object> but then as a consumer you have to cast to the right type when you read.
String homeName = (String) match.get("home_name");
Data objects allow the compiler to do a lot of compile-time checking that helps you know your code is correct. If you use a map, you won't find out until runtime.
Prompt the user separately for each input.
System.out.println("home_name: ");
String hN = scan.next();
System.out.println("away_name: ");
String aN = scan.next();
System.out.println("home_score: ");
String hS = scan.next();
System.out.println("away_score: ");
String aS = scan.next();

Sorting a linked list using insert sort method in Java

I have an assignment for my class to sort a LinkedList that we made previously using the insert sort method. We created the List by reading in an excel file with 5 contributors listed. I realize this sounds like a repeat question...however, all of the samples I can find deal with Integers or arrays, nothing that I can find deals with strings or with a LinkedList like the one I am using. The other problem, the examples I do find that deal with more than just integers assume you made the list "from scratch", using Head and Node and stuff like that...as you can see in my code, I did not make mine from scratch, I just used the build in Java utility to make mine. Anyways, my code may not be super efficient, but I got a 100 on every assignment so far, so it's good enough for the school I guess, but any suggestions to make it better are welcome as well. I am a beginner to programming, only experience I have is previous classes. So, here is my code:
import java.io.*;
import java.util.*;
public class ChrisJohnson_Unit3_IP {
static class Contributor{ //create class to store contributor information
//declare variables
private String firstName;
private String lastName;
private String country;
private String phone;
private double contribution;
private int id;
//methods for setting variable values
public String getFirstName(){
return firstName;
}
public void setFirstName(String firstName){
this.firstName = firstName;
}
public String getLastName(){
return lastName;
}
public void setLastName(String lastName){
this.lastName = lastName;
}
public String getCountry(){
return country;
}
public void setCountry(String country){
this.country = country;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone){
this.phone = phone;
}
public double getContribution(){
return contribution;
}
public void setContribution(double contribution){
this.contribution = contribution;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public void Print(){//method to print class objects
System.out.printf("%-10s %-10s %-8s %-15s %s %-15s %d %n", firstName, lastName, country,
phone, "$", contribution, id);
}
}//end Contributor class
static LinkedList contributorList = new LinkedList(); //create new Contributor Linked List
static Hashtable<String, Contributor> memberID = new Hashtable<>();//create new Hash Table
public static void main(String[] arg) throws Exception {
String response;
String ID;
Contributor contributorData = null;
Scanner in = new Scanner(System.in);
//print Welcome message and describe program to user
System.out.println("Welcome! This program will read your contributors.csv file "
+ "and store it into a list. \nTThe program will then sort the list and"
+ "print it for you to view/n");
System.out.println("Press enter to read the currently saved contributors.csv file...");
in.nextLine();
BufferedReader File =
new BufferedReader(new FileReader("contributors.csv"));
String dataRow = File.readLine(); // Read first line.
// The while checks to see if the data is null. If
// it is, end of file has been reached. If not,
// data will be processed.
while (dataRow != null){//While to read contributors.csv file and store in Contributor object
String[] data = dataRow.split(",");
contributorData = new Contributor(); //create new Contributor object
//store data into Contributor object
contributorData.setFirstName(data[0]);
contributorData.setLastName(data[1]);
contributorData.setCountry(data[2]);
contributorData.setPhone(data[3]);
contributorData.setContribution(Double.parseDouble(data[4]));
contributorData.setId(Integer.parseInt(data[5]));
ID = Integer.toString(contributorData.getId());
contributorList.push(contributorData);//add object to top of contributorList
memberID.put(ID,contributorData);//add contributor ID to key element of Hash Table
dataRow = File.readLine(); // Read next line of data.
}//end While to read contributors.csv file
File.close();//close CSV file
System.out.println("Here is your unsorted contributor list:\n");
//call Print method to print the list
System.out.printf("%-10s %-10s %-8s %-15s %-17s %s %n", "First", "Last",
"Country", "Phone #", "Contribution", "ID");
Iterator<Contributor> iter = contributorList.iterator();
while(iter.hasNext()){
iter.next().Print();
}//end while
System.out.println("Thank you for using this program!");
} //main()
}//end ChrisJohnson_Unit3_IP class
Again, the List has to be sorted by Name using the insert sort method. I understand the basic concept of the sort method, but honestly have no clue how to implement it here. I'm not looking for someone to do my homework for me, just give me a push in the right direction. Any help would be greatly appreciated, if you need anymore information please let me know. This assignment is due Monday, so hopefully someone is able to help me out by then. And yes, I have already written my instructor asking for help, I have been out of town all week so I have been trying to play catchup. Thank you for taking the time to read my question
First of all, I should say that doing an insertion sort on a linked list is totally pointless. Secondly, you could do something like the following, if you add a getName method that concatenates first and last names of the contributor (you can concatanate while sorting, but your code will be messier).
for( int i = 1; i < contributorList.size(); i++)
{
int j = i;
Contributor tmp;
while( j > 0 && contributorList.get(j-1).getName().compareTo( contributorList.get(j).getName()) > 0)
{
tmp = contributorList.remove( j);
contributorList.add( j-1, tmp);
j = j - 1;
}
}
First change your contributorList to use the Generic type of the objects it holds. That is LinkedList<Contributor>;. Second change the Object to implement Comparable. That is class Contributor implements Comparable<Contributor> and implement method public int compareTo(Contributor other). Third, pick a sorting method and implement it using compareTo to compare the objects for sorting.
Use ListIterator to find the correct point to insert the element and to the insertion. This allows you to do the insertion sort more efficiently than with the "standard approach", which would run in O(n³), since get and set runs in O(i) for index i. (The inner loop would run in O(i²), since O(1+2+...+i) = O(i²) and O(1²+2²+...+n²) = O(n³)).
Note that using a Iterator is enough to find the insertion point in O(n) and achieve O(n²) running time, but using ListIterator allows you to find and insert the element as well as remove the element for the next iteration of the outer loop iteration only a single iterator, if used in a clever way.
Using a Comparator to compare objects by a specified criterion also allows you to specify a criterion to sort by:
return value of comparator.compare(a, b) | meaning
-----------------------------------------------------------
0 | a == b
> 0 | a > b
< 0 | a < b
In java 8 you can easily create a Comparator given the method reference to a method returning the sort criterion given a object:
Comparator<Contributor> comparator = Comparator.comparing(Contributor::getLastName);
Without using method references this can be done using compareTo of a object implementing the Comparable interface, like String:
Comparator<Contributor> comparator = new Comparator<Contributor>() {
#Override
public int compare(Contributor o1, Contributor o2) {
return o1.getLastName().compareTo(o2.getLastName());
}
};
This way you use the Strategy Pattern for the ordering relation allowing you to use different sortings by passing different Comparators. And it's also the way the Collections class allows you to sort Lists with arbitrary contents, see Collections.sort(List, Comparator).

Return two string in toString function

#Entity
public class Person {
private Integer id = null;
private String name = null;
private String price = null;
private Date created = null;
// String Representation:
#Override
public String toString() {
return name;
// I want to return name and price
}
I want to return name and price in toString function ? This is right to return more than one string in toString function. If you make relation in other's Entity ManyToMany ?
Please suggest me if I am doing right or wrong as I want to show these fields in other entity where I make relations.
Thanks!
Usually the toString() method returns a string-representation of the object and not the object's members themself. So if you need a representation of name and price you could do
return "Name: " + name + ", Price: " + price;
If you really want to receive the members name and price you should generate getters for those and use them in the caller.
Another possibility is to "wrap" the two strings in some sort of data class.
This is right to return more than one string in toString function. If you make relation in other's Entity ManyToMany ?
That could be
#Override
public String toString() {
return "Name :" +name + " Price : "+price;
}
If you still have more Objects related to it, just append in the last. So that you won't loose information.
You can do it like this:
return name+" "+price;
You can create another method to return both.
you can return String array as well so that you don't need to split the string if you need to perform any operation on name and price.
You can use a StringBuilder and build up your composed String efficiently from both the name, the price and whatever you want.
Here the documentation.
Anyway, the response is no, you cannot send back two strings, but you can return a string that is a composition of the others.

Efficient way to split an array and organize into multiple array

I got a String[] which contains of multiple user details. Something like this:
Wilson#$20#$Male=#=Raymond#$25#$Male=#=Sophie#$20#$Female
I wanted to split the string up and organize it into multiple array. Such as one array for Name, one array for Age and another array for Gender. Up to this point I managed to split the String[] into something like this.
String[] User = student.split("=#=");
User[0] = Wilson#$20#$Male
User[1] = Raymond#$25#$Male
User[2] = Sophie#$20#$Female
I don't really know how to organize it from this point. Any comments and answers are highly appreciated!
EDIT
Wilson#$20#$Male=#=Raymond#$25#$Male=#=Sophie#$20#$Female
The above part is actually a value that is returned from the server and I wanted to handle this value. Thank you for all the replies. I think I understand a bit in theory wise, but I'm having slightly issue in implementing codes.
I agree with the suggestions of creating a class for each user - it's the Object Oriented way. So I included it in the example below. But you could probably change it easy enough if you want to do arrays or some other structure.
However, what I want to add is a way to use the Java classes java.util.regex.Pattern and java.util.regex.Matcher to extract both records AND fields in one go from your input string. (I haven't programmed for Android, I assume they are available though.)
The general plan for the pattern is: (record delimiter or nothing)(field1)(delim)(field2)(delim)(lastfield)(record delimiter + rest of input)
The algorithm basically loops through the input with the above pattern. The pattern extracts various groups for the fields (depending on how your record's format) and then also a last group that contains the remainder of the input string. This remainder is used as the new input string for the next loop. So each iteration of the loop does one record.
Here is more complete example code which you can run. You might need to study up on regular expressions to understand the pattern, which is the important part of the algorithm. You can start with the Javadoc for the java.util.regex.Pattern class.
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestPatternMatch {
public static void main(String[] args) {
List<User> result = new ArrayList<>();
String input =
"Wilson#$20#$Male=#=Raymond#$25#$Male=#=Sophie#$30#$Female";
Pattern recPatt =
Pattern.compile("^(=#=|.{0})(.+?)#\\$(\\d+)#\\$(.+?)(?==#=)(.*$)");
// ^match start of line
// ^match record delimiter or nothing
// ^match name field (reluctant)
// ^match field delim
// ^match age field
// ^match field delim
// match gender field^
// zero-width (non recording) lookahead for record delimiter^
// match rest of line until end^
Matcher recMatcher;
String workStr = input; // start with whole input
while (workStr != null && workStr.length() > 0) {
recMatcher = recPatt.matcher(workStr);
if (recMatcher.matches() && recMatcher.groupCount() >= 5) {
result.add(
new User(
recMatcher.group(2), //name
Integer.parseInt(recMatcher.group(3)), //age
recMatcher.group(4) //gender
)
);
workStr = recMatcher.group(5); // use tail for next iteration
} else {
workStr = null;
}
}
System.out.println(result); //show result list contents
}
}
class User {
String name;
int age;
String gender;
/** All argument constructor */
public User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/** Show contents of object fields */
public String toString() {
return "User ["+ name + ", " + age + ", " + gender + "]";
}
}
The basic pattern structure can be reused for many different record formats.
Create a User object to store all fields (name, age, gender) and create a list to hold all data.
Your best bet here, is to use an object to hold these values. Objects are the standardized way to hold values that relate to one another, in one Object. ie:
public class Person
{
private String name;
private int age;
private String gender;
// Gender could be a boolean value really, but you've stored it as a String.
}
In the constructor you would request each value and assign it to these fields. It would look something like:
public Person(String name, int age, String gender)
{
this.name = name;
// etc etc
}
That way you have one array, with no need to do any tokenizing of Strings to get to individual values :). You will also need to implement some Accessors and Mutators to get at the values within the Object.
Why not create a User class and maintain a list of User instances.
class User {
String name;
String gender;
int age;
}
The best solution would be to create an class User. If you want to avoid it, try:
String[] User = student.split("=#=");
String [][] details=new String[user.length][3];
String [] temp=new String[3];
for(int i=0;i<User.length;i++){
temp=User.split("//");
for(j=0;j<3;j++){
details[i][j]=temp[j];
}
}

Categories

Resources