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];
}
}
Related
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) {
}
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();
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).
I have a class Passengers which has member properties String name, int health, and String disease with setter and getter methods. The disease variable will initially hold null. Here's that class
public class Passengers
{
private String name;
private int health;
private String disease;
public Passengers(String _name, int _health, String _disease)
{
name = _name;
health = _health;
disease = _disease;
}
public void setHealth(int _health)
{
health = _health;
}
public void setDisease(String _disease)
{
disease = _disease;
}
public String getName()
{
return name;
}
public int getHealth()
{
return health;
}
public String getDisease()
{
return disease;
}
}
What I want to know is how I could add new strings onto this variable, and then how to take away. For example, a passenger Bill starts at null for his diseases, and then contracts malaria and the cold. Bill's disease variable should now hold malaria, cold. Now say the user chooses to treat Bill's malaria. How would I
1) add malaria and cold
2) subtract just malaria from disease?
Whenever I attempt to change the disease with
passengers[index].setDisease() = null;
it says "error: method setDisease in class Passengers cannot be applied to given types:
required: String
found: no arguments"
I would reccomend making disease a Set of Strings.
Set<String> diseases = new HashSet<String>();
void addDisease(String disease) {
diseases.add(disease);
}
void removeDisease(String deisease) {
diseases.remove(disease);
}
Sets are "better", in this case, than other Collections because they cannot hold duplicates.
You should give the class a List<String> such as an ArrayList<String> and put the diseases in this List.
Better still, create a class or enum of Disease and have your Passenger class use a List<Disease> and avoid over-use of String. You could then give the class public addDisease(Disease disease) and removeDisease(Disease disease) methods.
Incidentally, your class above should be named Passenger, the singular, not Passengers, the plural, since it represents the concept of a single Passenger.
For your requirement if you are using List like ArrayList you can access your elements(disease names) by index, but it will allow duplicate data to be inserted(same disease may be added multiple times, it will unnecessary increase in number of diseases and may arise some problems).
If you use Set like HashSet it will allow unique element only, so no issues related to duplicated entries but at the same time you can't access a particular disease by index (if you need so, as of now I am not aware of your further requirement).
So as best of my knowledge I suggest you to use LinkedHashSet(HashSet with Linked approach) it will provide you FIFO order without duplicate insertion problem.
ID Name Department Salary Designation
---------------------------------------
1 Kent Engineering 100000$ senior-engineer
2 Smith null 50,000$ administrator
These are the records of a big file I have. I need to parse this file to retrieve salary and designation. The key has to be ID,Name,Department and if that fails then use ID,Name ..
I can only use Java/groovy to do this... How do I get <Salary,Designation> back... ?
What's the most efficient way to grep it given that i can use only java/groovy
Create a BufferedReader, this will allow you to read the file one line at a time. Then call split("[\\\s]") on each of the lines, this will split it by whitespace.
You may also have to massage the salary field so it can be parsed into a number.
Split each line on whitespace.
scala> val a = "1 Kent Engineering 100000$ senior-engineer"
a: java.lang.String = 1 Kent Engineering 100000$ senior-engineer
scala> a.split("\\s+")
res1: Array[java.lang.String] = Array(1, Kent, Engineering, 100000$, senior-engineer)
Then take the raw string values and parse those. E.g. to convert 50,000$ into the number 50000:
double salary = Double.parseDouble(array[SALARY_INDEX].replaceAll("[$,]",""))
java.lang.Double.parseDouble("50,000$".replaceAll("[$,]",""))
res6: Double = 50000.0
You can parse the file into a HashMap and keep it around as long as you need it.
It has a high up-front cost, but if you're going to use it a lot, then it makes sense.
Then create your key and value objects. Be sure to override equals for your key.
public class Key{
int id;
String name;
#Override
public boolean equals(Object o){...}
}
I'll assume that you're aware of how to read files line-by-line using a BufferedReader as that's an obvious prerequisite for this sort of thing - if not, shout.
The key is the thing that you've failed to specify. What, exactly, is the format of the data - in particular, what are the exact rules for determining where one field ends and the other begins?
If the data is separated by tab characters (and said characters are forbidden from occurring in the data, even if escaped) then the solution is simple:
// Ignoring general error handling and EOF-checking here
final String line = bufferedReader.readLine();
final String[] fields = line.split("\t");
Now you have an array containing the fields on the line, so can just look up fields[3] and fields[4].
If the separator is "any number of spaces", and spaces are entirely disallowed, then you've got a similarly easy situation, where your regex is line.split(" *").
In more complex situations, including ones where separators are allowed to appear if escaped or quoted, you may be better off simply iterating over the line character-by-character and manually building up the set of fields according to the separator rules.
With a pinch of Guava library, the solution is simple and elegant. We can improve the below code by objectifying the key, handling errors etc etc but you can do that yourself
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import com.google.common.base.CharMatcher;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.common.io.LineProcessor;
public class FileProcessor
{
private static final Splitter SPLITTER = Splitter.on(CharMatcher.WHITESPACE);
private static final Joiner KEY_BUILDER = Joiner.on("_").skipNulls();
#SuppressWarnings("unchecked")
public static void main(final String[] args) throws IOException
{
Map<String, SalaryAndDesignation> result = Files.readLines(new File("c:/1.txt"), Charsets.ISO_8859_1, new LineProcessor() {
private final Map<String, SalaryAndDesignation> result = Maps.newHashMap();
public Object getResult()
{
return result;
}
public boolean processLine(final String line) throws IOException
{
Iterator<String> columns = SPLITTER.split(line).iterator();
String id = columns.next();
String name = columns.next();
String dept = columns.next();
String key = KEY_BUILDER.join(id, name, "null".equals(dept) ? null : dept);
result.put(key, new SalaryAndDesignation(columns.next(), columns.next()));
return true;
}
});
System.out.println(result.size());
}
final static class SalaryAndDesignation
{
String salary;
String designation;
public SalaryAndDesignation(final String salary, final String designation)
{
super();
this.salary = salary;
this.designation = designation;
}
}
}
I see using groovy results in lesser code as sample below (copy/pasted from here) but never used it myself
new File("simple.tab").withReader{r->
line = r.readLine();
println "first line: $line"
r.splitEachLine("\t"){fields->
println "fields on line: $fields"
}
}