diff --git a/feedback.txt b/feedback.txt index b931d50..0c3b98d 100644 --- a/feedback.txt +++ b/feedback.txt @@ -1,9 +1,7 @@ -Your team (name of each individual participating): -How many JUnits were you able to get to pass? +Your team (name of each individual participating): Stuart Irwin +How many JUnits were you able to get to pass? 10 Document and describe any enhancements included to help the judges properly grade your submission. - Step 1: - Step 2: Feedback for the coding competition? Things you would like to see in future events? diff --git a/pom.xml b/pom.xml index 21d55bf..c35e2ff 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,19 @@ 4.0.0 coding-competition 1.0.0-SNAPSHOT - jar + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + jar sf.codingcompetition2020 coding-competition diff --git a/src/main/java/sf/codingcompetition2020/CodingCompCsvUtil.java b/src/main/java/sf/codingcompetition2020/CodingCompCsvUtil.java index 58267da..c936ea2 100644 --- a/src/main/java/sf/codingcompetition2020/CodingCompCsvUtil.java +++ b/src/main/java/sf/codingcompetition2020/CodingCompCsvUtil.java @@ -1,20 +1,9 @@ package sf.codingcompetition2020; -import java.io.FileReader; -import java.io.Reader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.MappingIterator; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.dataformat.csv.CsvMapper; -import com.fasterxml.jackson.dataformat.csv.CsvSchema; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; +import java.util.function.Predicate; import sf.codingcompetition2020.structures.Agent; import sf.codingcompetition2020.structures.Claim; @@ -30,7 +19,42 @@ public class CodingCompCsvUtil { * @return -- List of entries being returned. */ public List readCsvFile(String filePath, Class classType) { - + return readCsvFile(filePath, classType, null); + } + + private List readCsvFile(String filePath, Class classType, Predicate filter) { + //Open file + File file = new File(filePath); + ArrayList list = new ArrayList<>(); + try { + //Skip first line + Scanner scan = new Scanner(file); + scan.nextLine(); + + while(scan.hasNextLine()) { + + //Build object + String[] values = scan.nextLine().split(","); + T ob = readLine(values, classType); + if(filter == null || filter.test(ob)) + list.add(ob); + } + } catch(FileNotFoundException e) { + System.out.println("File " + filePath + " not found"); + } + return list; + } + + private T readLine(String[] input, Class classType) { + if(classType == Agent.class) + return (T) new Agent(input); + if(classType == Claim.class) + return (T) new Claim(input); + if(classType == Customer.class) + return (T) new Customer(input); + if(classType == Vendor.class) + return (T) new Vendor(input); + throw new IllegalArgumentException("Invalid class type"); } @@ -40,8 +64,8 @@ public List readCsvFile(String filePath, Class classType) { * @param area -- The area from which the agents should be counted. * @return -- The number of agents in a given area */ - public int getAgentCountInArea(String filePath,String area) { - + public int getAgentCountInArea(String filePath, String area) { + return readCsvFile(filePath, Agent.class, agent -> agent.getArea().equals(area)).size(); } @@ -53,7 +77,7 @@ public int getAgentCountInArea(String filePath,String area) { * @return -- The number of agents in a given area */ public List getAgentsInAreaThatSpeakLanguage(String filePath, String area, String language) { - + return readCsvFile(filePath, Agent.class, agent -> agent.getArea().equals(area) && agent.getLanguage().equals(language)); } @@ -66,7 +90,13 @@ public List getAgentsInAreaThatSpeakLanguage(String filePath, String area * @return -- The number of customers that use a certain agent in a given area. */ public short countCustomersFromAreaThatUseAgent(Map csvFilePaths, String customerArea, String agentFirstName, String agentLastName) { - + List agents = readCsvFile(csvFilePaths.get("agentList"), Agent.class, + agent -> agent.getFirstName().equals(agentFirstName) && agent.getLastName().equals(agentLastName)); + if(agents.size() != 1) + return 0; + + return (short)readCsvFile(csvFilePaths.get("customerList"), Customer.class, + customer -> customer.getArea().equals(customerArea) && customer.getAgentId() == agents.get(0).getAgentId()).size(); } @@ -77,7 +107,9 @@ public short countCustomersFromAreaThatUseAgent(Map csvFilePaths, * @return -- List of customers retained for a given number of years, in ascending order of policy cost. */ public List getCustomersRetainedForYearsByPlcyCostAsc(String customerFilePath, short yearsOfService) { - + List customers = readCsvFile(customerFilePath, Customer.class, customer -> customer.getYearsOfService() == yearsOfService); + customers.sort(Comparator.comparingInt(customer -> Integer.parseInt(customer.getTotalMonthlyPremium().substring(1)))); + return customers; } @@ -88,7 +120,8 @@ public List getCustomersRetainedForYearsByPlcyCostAsc(String customerF * @return -- List of customers who’ve made an inquiry for a policy but have not signed up. */ public List getLeadsForInsurance(String filePath) { - + return readCsvFile(filePath, Customer.class, customer -> + !(customer.hasAutoPolicy() || customer.hasHomePolicy() || customer.hasRentersPolicy())); } @@ -103,7 +136,8 @@ b. Whether that vendor is in scope of the insurance (if inScope == false, return * @return -- List of vendors within a given area, filtered by scope and vendor rating. */ public List getVendorsWithGivenRatingThatAreInScope(String filePath, String area, boolean inScope, int vendorRating) { - + return readCsvFile(filePath, Vendor.class, + vendor -> vendor.getArea().equals(area) && vendor.getVendorRating() >= vendorRating && (!inScope || vendor.isInScope())); } @@ -117,7 +151,9 @@ public List getVendorsWithGivenRatingThatAreInScope(String filePath, Str * @return -- List of customers filtered by age, number of vehicles insured and the number of dependents. */ public List getUndisclosedDrivers(String filePath, int vehiclesInsured, int dependents) { - + return readCsvFile(filePath, Customer.class, + customer -> customer.getVehiclesInsured() > vehiclesInsured && customer.getDependents().size() <= dependents && + customer.getAge() >= 40 && customer.getAge() <= 50); } @@ -130,8 +166,30 @@ public List getUndisclosedDrivers(String filePath, int vehiclesInsured * @return -- Agent ID of agent with the given rank. */ public int getAgentIdGivenRank(String filePath, int agentRank) { - - } + List list = readCsvFile(filePath, Customer.class); + HashMap agents = new HashMap<>(); + + //Create map of agent ratings + for(Customer c : list) { + int agentId = c.getAgentId(); + if(agents.containsKey(agentId)) + agents.replace(agentId, agents.get(agentId).add(new Pair(c.getAgentRating(), 1))); + else + agents.put(agentId, new Pair(c.getAgentRating(), 1)); + } + + //Create new list + List agentsList = new ArrayList<>(); + for(int agentId : agents.keySet()) { + //Calculate avg rating + Pair p = agents.get(agentId); + agentsList.add(new Pair(agentId, 100 * p.first / p.second)); + } + + //Sort agents + agentsList.sort(Comparator.comparingInt(pair -> pair.second)); + return agentsList.get(agentsList.size() - agentRank).first; + } /* #10 @@ -141,7 +199,14 @@ public int getAgentIdGivenRank(String filePath, int agentRank) { * @return -- List of customers who’ve filed a claim within the last . */ public List getCustomersWithClaims(Map csvFilePaths, short monthsOpen) { - + List claims = readCsvFile(csvFilePaths.get("claimList"), Claim.class, claim -> claim.getMonthsOpen() <= monthsOpen); + List customers = readCsvFile(csvFilePaths.get("customerList"), Customer.class); + Set filteredCustomers = new HashSet<>(); + + for(Claim c : claims) + filteredCustomers.add(customers.get(c.getCustomerId() - 1)); + + return new ArrayList<>(filteredCustomers); } } diff --git a/src/main/java/sf/codingcompetition2020/Pair.java b/src/main/java/sf/codingcompetition2020/Pair.java new file mode 100644 index 0000000..838ada3 --- /dev/null +++ b/src/main/java/sf/codingcompetition2020/Pair.java @@ -0,0 +1,15 @@ +package sf.codingcompetition2020; + +public class Pair { + public final int first; + public final int second; + + public Pair(int first, int second) { + this.first = first; + this.second = second; + } + + public Pair add(Pair other) { + return new Pair(first + other.first, second + other.second); + } +} diff --git a/src/main/java/sf/codingcompetition2020/structures/Agent.java b/src/main/java/sf/codingcompetition2020/structures/Agent.java index e2e6f93..df272c8 100644 --- a/src/main/java/sf/codingcompetition2020/structures/Agent.java +++ b/src/main/java/sf/codingcompetition2020/structures/Agent.java @@ -8,4 +8,35 @@ public class Agent { private String firstName; private String lastName; + public Agent(String[] s) { + if(s.length != 5) + return; + + //Set values + agentId = Integer.parseInt(s[0]); + area = s[1]; + language = s[2]; + firstName = s[3]; + lastName = s[4]; + } + + public int getAgentId() { + return agentId; + } + + public String getArea() { + return area; + } + + public String getLanguage() { + return language; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } } diff --git a/src/main/java/sf/codingcompetition2020/structures/Claim.java b/src/main/java/sf/codingcompetition2020/structures/Claim.java index 581140a..af61687 100644 --- a/src/main/java/sf/codingcompetition2020/structures/Claim.java +++ b/src/main/java/sf/codingcompetition2020/structures/Claim.java @@ -6,4 +6,30 @@ public class Claim { private boolean closed; private int monthsOpen; + public Claim(String[] s) { + if(s.length != 4) + return; + + //Set values + claimId = Integer.parseInt(s[0]); + customerId = Integer.parseInt(s[1]); + closed = s[2].equals("true"); + monthsOpen = Integer.parseInt(s[3]); + } + + public int getClaimId() { + return claimId; + } + + public int getCustomerId() { + return customerId; + } + + public boolean isClosed() { + return closed; + } + + public int getMonthsOpen() { + return monthsOpen; + } } diff --git a/src/main/java/sf/codingcompetition2020/structures/Customer.java b/src/main/java/sf/codingcompetition2020/structures/Customer.java index f151906..0675d10 100644 --- a/src/main/java/sf/codingcompetition2020/structures/Customer.java +++ b/src/main/java/sf/codingcompetition2020/structures/Customer.java @@ -3,10 +3,6 @@ import java.util.ArrayList; import java.util.List; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; - public class Customer { private int customerId; private String firstName; @@ -23,5 +19,94 @@ public class Customer { private String totalMonthlyPremium; private short yearsOfService; private Integer vehiclesInsured; + + public Customer(String[] s) { + if(s.length < 15) + return; + + //First set of values + customerId = Integer.parseInt(s[0]); + firstName = s[1]; + lastName = s[2]; + age = Integer.parseInt(s[3]); + area = s[4]; + agentId = Integer.parseInt(s[5]); + agentRating = Short.parseShort(s[6]); + primaryLanguage = s[7]; + + //Variable number of dependents + int i = 0; + dependents = new ArrayList<>(); + if(s[8].length() > 0) { + do { + dependents.add(new Dependent(s[8 + i], s[9 + i])); + i += 2; + } while(s[8 + i].charAt(0) == '{'); + i--; + } + + //Other variables offset accordingly + homePolicy = s[9 + i].equals("true"); + autoPolicy = s[10 + i].equals("true"); + rentersPolicy = s[11 + i].equals("true"); + totalMonthlyPremium = s[12 + i]; + yearsOfService = Short.parseShort(s[13 + i]); + vehiclesInsured = Integer.parseInt(s[14 + i]); + } + + public int getCustomerId() { + return customerId; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public int getAge() { + return age; + } + + public String getArea() { + return area; + } + + public int getAgentId() { + return agentId; + } + + public short getAgentRating() { + return agentRating; + } + + public List getDependents() { + return dependents; + } + + public boolean hasHomePolicy() { + return homePolicy; + } + + public boolean hasAutoPolicy() { + return autoPolicy; + } + + public boolean hasRentersPolicy() { + return rentersPolicy; + } + + public String getTotalMonthlyPremium() { + return totalMonthlyPremium; + } + + public int getYearsOfService() { + return yearsOfService; + } + public Integer getVehiclesInsured() { + return vehiclesInsured; + } } diff --git a/src/main/java/sf/codingcompetition2020/structures/Dependent.java b/src/main/java/sf/codingcompetition2020/structures/Dependent.java index d4deb1a..ce42ebb 100644 --- a/src/main/java/sf/codingcompetition2020/structures/Dependent.java +++ b/src/main/java/sf/codingcompetition2020/structures/Dependent.java @@ -4,4 +4,9 @@ public class Dependent { private String firstName; private String lastName; + public Dependent(String first, String last) { + //Clean json data + firstName = first.split(":")[1].replaceAll("[\"}]",""); + lastName = last.split(":")[1].replaceAll("[\"}]",""); + } } diff --git a/src/main/java/sf/codingcompetition2020/structures/Vendor.java b/src/main/java/sf/codingcompetition2020/structures/Vendor.java index 6b6fb76..d6824e2 100644 --- a/src/main/java/sf/codingcompetition2020/structures/Vendor.java +++ b/src/main/java/sf/codingcompetition2020/structures/Vendor.java @@ -5,5 +5,31 @@ public class Vendor { private String area; private int vendorRating; private boolean inScope; - + + public Vendor(String[] s) { + if(s.length != 4) + return; + + //Set values + vendorId = Integer.parseInt(s[0]); + area = s[1]; + vendorRating = Integer.parseInt(s[2]); + inScope = s[3].equals("true"); + } + + public int getVendorId() { + return vendorId; + } + + public String getArea() { + return area; + } + + public int getVendorRating() { + return vendorRating; + } + + public boolean isInScope() { + return inScope; + } } diff --git a/src/main/resources/schema.graphqls b/src/main/resources/schema.graphqls new file mode 100644 index 0000000..05eb4b2 --- /dev/null +++ b/src/main/resources/schema.graphqls @@ -0,0 +1,51 @@ +type Agent { + agentId: ID! + area: String + language: String + firstName: String + lastName: String +} + +type Dependent { + firstName: String + lastName: String +} + +type Customer { + customerId: ID! + firstName: String + lastName: String + age: Int + area: String + agentId: Int + agentRating: Int + primaryLanguage: String + dependents: [Dependent] + homePolicy: Boolean + autoPolicy: Boolean + rentersPolicy: Boolean + totalMonthlyPremium: String + yearsOfService: Int + vehiclesInsured: Int +} + +type Claim { + claimId: ID! + customer: Customer + closed: Boolean + monthsOpen: Int +} + +type Vendor { + vendorId: ID! + area: String + vendorRating: Int + inScope: Boolean +} + +type Query { + agents: [Agent] + claims: [Claim] + customers: [Customer] + vendors: [Vendor] +} \ No newline at end of file diff --git a/target/classes/sf/codingcompetition2020/CodingCompCsvUtil.class b/target/classes/sf/codingcompetition2020/CodingCompCsvUtil.class index 00daba9..09b9782 100644 Binary files a/target/classes/sf/codingcompetition2020/CodingCompCsvUtil.class and b/target/classes/sf/codingcompetition2020/CodingCompCsvUtil.class differ diff --git a/target/classes/sf/codingcompetition2020/structures/Agent.class b/target/classes/sf/codingcompetition2020/structures/Agent.class index 26bf31f..021e4f8 100644 Binary files a/target/classes/sf/codingcompetition2020/structures/Agent.class and b/target/classes/sf/codingcompetition2020/structures/Agent.class differ diff --git a/target/classes/sf/codingcompetition2020/structures/Claim.class b/target/classes/sf/codingcompetition2020/structures/Claim.class index 1ce796d..0e79a6a 100644 Binary files a/target/classes/sf/codingcompetition2020/structures/Claim.class and b/target/classes/sf/codingcompetition2020/structures/Claim.class differ diff --git a/target/classes/sf/codingcompetition2020/structures/Customer.class b/target/classes/sf/codingcompetition2020/structures/Customer.class index 844ea29..10fa7f9 100644 Binary files a/target/classes/sf/codingcompetition2020/structures/Customer.class and b/target/classes/sf/codingcompetition2020/structures/Customer.class differ diff --git a/target/classes/sf/codingcompetition2020/structures/Dependent.class b/target/classes/sf/codingcompetition2020/structures/Dependent.class index 3ee505f..41b1be7 100644 Binary files a/target/classes/sf/codingcompetition2020/structures/Dependent.class and b/target/classes/sf/codingcompetition2020/structures/Dependent.class differ diff --git a/target/classes/sf/codingcompetition2020/structures/Vendor.class b/target/classes/sf/codingcompetition2020/structures/Vendor.class index fdbca9b..c537673 100644 Binary files a/target/classes/sf/codingcompetition2020/structures/Vendor.class and b/target/classes/sf/codingcompetition2020/structures/Vendor.class differ diff --git a/target/test-classes/sf/codingcompetition2020/CodingCompCsvUtilTest.class b/target/test-classes/sf/codingcompetition2020/CodingCompCsvUtilTest.class index 765ac60..7efe870 100644 Binary files a/target/test-classes/sf/codingcompetition2020/CodingCompCsvUtilTest.class and b/target/test-classes/sf/codingcompetition2020/CodingCompCsvUtilTest.class differ