Java: using string wildcards/regex as the key of a map - java

I have a small java project which tries to match a given customer record with one in a database based on closest match.
A given customer has a unique combination of String variables-
Name, Address1, Address2
If some data is missing then the default for a given variable is "ALL".
The code retrieves all the database records and creates a map of customer records where customerKey is a unique combination of name, address1, address2.
CustomerKey is a class of these string variables with their own getters/setters and hashcode (from apache HashCodeBuilder).
CustomerData is just a dump of all the data in the record for that customer in the database
The code works as normal so far
String name = "Harry";
String address1 = "hello street";
String address2 = "hello town";
map<customerKey, CustomerData> lookupMap = getDataFromDB();
CustomerData data = lookupMap.get(new CustomerKey(name, address1, address2));
if (data==null){
data = lookupMap.get(new CustomerKey("ALL", address1, address2));
}
if (data==null){
data = lookupMap.get(new CustomerKey("ALL", "ALL", address2));
}
if (data==null){
data = lookupMap.get(new CustomerKey("ALL", "ALL", "ALL"));
}
return data
I want to be able to add wildcards to the matching process where it is applied to the names. I can find out the regex for what i want e.g. .*arry and add that to the name of a particular record.
And i know that if i want to use wild card comparisons of strings then i need to use .matches rather than .equals (e.g. "harry".matches(".*arry").
But i'm having some difficulty moving forward from there.
Does anyone have some advice?

Related

How to parse String and send multiple values to constructor

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) {
}

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();

Dealing with .CSV files and sorting a listarrays into multiple listarrays? - JAVA

So i am trying to sort through a large amount of data in an CSV. file. The file includes a set amount of information for companies, but there are 1000s of companies. For example, I might need to go through 1000 companies, be able to acquire their annual earnings, current stock value, CEO, ect.. each company will have the same information provided (same number of commas but different char lengths), but as the file is a CSV. the company name and information is all separated by commas.
currently i am splitting the csv file into an array via the commas between information. But i want to be able to keep the information together with companies and be able to specify, call and, sort by the given information and company names. But because i have already separated the information via the commas its all listed out already in a listarray.
So is it possible to specify, on a mass scale, that every 15 commas (or splits in the listarray) should be joined back together?? This way each part of the listarray is a separate company. Or is there another way to separate the data so that the information doesnt get split up?
note: there is no similarities in the csv file that would allow me to split information so that it splits after each companies information.
here is a sample of what one of the csv files may look like.
"Tiffany & Co. Com",964270,"+0.81","1/14/2014",88.97,93.64,"87.795 - 88.97""Asia Pacific Fund",20700,"+0.04","1/14/2014",10.23,11.37,"10.19 - 10.23""Anadarko Petroleu",4236380,"+2.47","1/14/2014",80.99,98.47,"78.40 - 80.99""Proto Labs, Inc. ",451984,"-0.18","1/14/2014",73.83,89.97,"71.00 - 73.83""Zuoan Fashion Lim",201560,"-0.02","1/14/2014",1.79,3.62,"1.71 - 1.79"
I would agree with converting each row of CSV into Java object.
But traditional parsing mechanism is too verbose for me and I might need to handle too many conditions like comma in between quotes, new line character in a column with multiline description. So I suggest you use an existing awesome solution like supercsv.
I also have written a wrapper around it to make developer life easy.
QuickOCM will let you do this way.
Create a Company class
public class Company {
/* this specifies that
* it is a mandatory field in the csv,
* of header name "Company Name" and
* of type string.
* Header is the first line of the csv.
*/
#ImportField(mandatory = true, name = "Company Name", type = "String")
public String name;
#ImportField(mandatory = true, name = "Name of the CEO", type = "String")
public String ceoName;
}
You need public getter-setter or public fields, anything works
Create csv parser, a handler to handle each row, probably add to a list to sort, and then call parse
final List<Company> companies = new ArrayList<Company>();
csvParser.process(inputStream, Company.class, new RecordHandler<Company>() {
#Override
public void execute(Company imported, int rowNumber, Map supplementaryInfo) {
companies.add(imported);
}
});
Now you can sort the list with by using a sorted list implementation or use a comparator for the same.
For detailed info, you can look into QuickOCM page.
public class Read{
String original = "";
String company = "";
String otherValue = "";
public Read(String read){
//here Split the original string into the values
}
//public void getters and setters
}
Then make an array of Read Objects and sort them as you want
One idea would be to parse the CSV into objects and then sort those objects. The object would "know" how many fields it was made up of in the CSV and how to parse each field. Using the StringTokenizer to parse and a TreeMap to sort would look something like:
...
BufferedReader reader = new BufferedReader(new FileReader("somedata.csv"));
TreeMap<String, MyObject> map = new TreeMap<>();
String line = reader.readLine();
StringTokenizer tokens = new StringTokenizer(line,",");
while(tokens.hasMoreTokens()) {
MyObject obj = new MyObject(tokens);
//add the objects to the sorted map, where field1 is what we sort on
map.put(obj.field1, obj);
}
...
}
static class MyObject {
//would need the same number of fields as you want to group
String field1;
String field2;
//... so with 2 fields, input is field1,field2,field1,field2,...
MyObject (StringTokenizer input) {
this.field1 = input.nextToken();
this.field2 = input.nextToken();
}
}

Table storage for strings and booleans

I've implemented in-app-billing v3 and I'd like a way to keep some sort of table which contains 3 columns
(String) Name of product, (String) sku, (boolean) true/false
What is the best way to do this? The best way would (in my opinion) allow me to keep a static easily readable list of values where the first two were strings, the third a boolean. At the start all the values for the boolean column were false, but as I query purchases I am able to easily reset the value.
Just to add,
I'm against SQLite databases for the reason that they're just too easy to hack. I'd rather create it in code and thus I'm debating between an ArrayList within an arraylist or matrices or something like the following:
private static class CatalogEntry {
public String sku;
public String name;
public CatalogEntry(String sku, String name) {
this.sku = sku;
this.name = name;
}
}
private static final CatalogEntry[] CATALOG = new CatalogEntry[] {
new CatalogEntry("android.test.purchased", "Item1"),
new CatalogEntry("android.test.canceled", "Item2"),
new CatalogEntry("android.test.refunded", "Item3"),
new CatalogEntry("android.test.item_unavailable", "Item4")
};
Is there a way to reset values in the CATALOG array if I add a third column, otherwise I'm considering using both that and standard arraylists.
Use sqlite with FOUR columns:
sku
name
purchaseDate (or null if not purchased)
md5Hash
When a purchase is made, you just concatenate the sku, name, purchaseDate, device-id, and a PSK, make an md5Hash and store it along with the other data in the row. When you check the contents of the table, you compare the md5 stored against the data, and you can verify whether the purchase was valid, or the table has been tampered with. You can even let the user back up the purchase table to sdcard (or use Android backup).

GWT RPC match data for CellTable

I have a GWT 2.4 project using a CellTable.
It has columns like this (actually more):
LastName --- FirstName --- Departments
Smith Tom Research, Management
The names I get from a "User" object which is created on the server from my Database.
The DB looks like this:
users:
userID
firstName
lastName
departments:
departmentID
departmentName
user_in_department:
userID
departmentID
So what is the best way to get my departments show up in the table?
At the moment I fetch the User-list and the Department-list from the server using a RPC.
I thought about a 3rd RPC to get me the user-department relation and then match the names to the users on the client. What would be a good way to match that btw?
But even if I had the departments matched to my users, how would I add that info to the table?
For the names I can just do that:
TextColumn<User> firstNameColumn = new TextColumn<User>() {
#Override
public String getValue(User object) {
return object.getFirstName();
}
};
But as the departments aren't stored in the "User" object, I have no idea how to get them in the correct column and row.
I hope I've explained my issue good enough for you to understand :)
Assuming that your User object has a list of departments like so:
public ArrayList<Department> getDepartments() {
// ...
}
You can create a column to list the departments like so:
TextColumn<User> departmentsColumn = new TextColumn<User>() {
#Override
public String getValue(User object) {
StringBuilder departments = new StringBuilder();
for(int i=0; i < object.getDepartments().size(); i++) {
if (i>0) {
departments.append(",");
}
departments.append(object.getDepartments().get(i).getDepartmentName());
}
return departments.toString();
}
};
In addition to the first answer: since a CellTable is parameterized to display a list of objects of a given type in its rows that object should include the user name as well as a list of departments. You'll have to somehow make that data available through the User object, or create a new one (e.g. UserDepartmentDTO) as the elements in the underlying model.

Categories

Resources