diff --git a/feedback.txt b/feedback.txt index 8234592..3edffff 100644 --- a/feedback.txt +++ b/feedback.txt @@ -1,9 +1,12 @@ -Your team (name of each individual participating): -How many JUnits were you able to get to pass? +Your team (name of each individual participating): Harshal Sheth, Ankur Sundara +How many JUnits were you able to get to pass? 10/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? \ No newline at end of file + Step 0: We added a web-based frontend for visualizing and interacting with the provided data. + Step 1: To use it, simply open the `webui/Main.java` file, and click the green arrow + beside the Main class. Click the option for 'Run Main.main()'. + Step 2: Once our server has started, navigate to http://localhost:4567 in a browser, and + follow the instructions on using our tool. + +Feedback for the coding competition? Things you would like to see in future events? +The competition was extremely fun! \ No newline at end of file diff --git a/pom.xml b/pom.xml index 78eb746..5090d2f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,19 @@ codingcompetition2019 codingcompetition2019 0.0.1-SNAPSHOT - jar + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + jar codingcompetition2019 http://maven.apache.org @@ -16,11 +28,26 @@ + + com.google.code.gson + gson + 2.8.5 + + + com.sparkjava + spark-core + 2.8.0 + junit junit 4.12 test + + org.slf4j + slf4j-nop + 1.7.28 + diff --git a/src/main/java/codingcompetition2019/CodingCompCSVUtil.java b/src/main/java/codingcompetition2019/CodingCompCSVUtil.java index 74f3074..326761b 100644 --- a/src/main/java/codingcompetition2019/CodingCompCSVUtil.java +++ b/src/main/java/codingcompetition2019/CodingCompCSVUtil.java @@ -1,44 +1,74 @@ package codingcompetition2019; import java.io.IOException; +import java.nio.file.*; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class CodingCompCSVUtil { - public List> readCSVFileByCountry(String fileName, String countryName) throws IOException { - // TODO implement this method - return null; - } - - public List> readCSVFileWithHeaders(String fileName) throws IOException { - // TODO implement this method - return null; - } - - public List> readCSVFileWithoutHeaders(String fileName) throws IOException { - // TODO implement this method - return null; - } - - public DisasterDescription getMostImpactfulYear(List> records) { - // TODO implement this method - return null; - } + private Stream> readCSVStream(String fileName) throws IOException { + Path file = Paths.get(fileName); + return Files.lines(file).map(line -> { + String[] lineContents = line.split(","); + return Arrays.asList(lineContents); + }); + } - public DisasterDescription getMostImpactfulYearByCategory(String category, List> records) { - // TODO implement this method - return null; - } + public List> readCSVFileByCountry(String fileName, String countryName) throws IOException { + return readCSVStream(fileName).filter( + line -> countryName.equals(line.get(0)) + ).collect(Collectors.toList()); + } - public DisasterDescription getMostImpactfulDisasterByYear(String year, List> records) { - // TODO implement this method - return null; - } + public List> readCSVFileWithHeaders(String fileName) throws IOException { + return readCSVStream(fileName).collect(Collectors.toList()); + } + + public List> readCSVFileWithoutHeaders(String fileName) throws IOException { + return readCSVStream(fileName).skip(1).collect(Collectors.toList()); + } + + private DisasterDescription getMostImpactfulDisaster(Stream ddStream) { + return ddStream.max( + Comparator.comparingInt( + DisasterDescription::getReportedIncidentsNum + ) + ).orElseThrow(() -> new IllegalArgumentException("records must not be empty")); + } + + public DisasterDescription getMostImpactfulYear(List> records) { + Stream dds = records.stream() + .map(DisasterDescription::new); + return getMostImpactfulDisaster(dds); + } + + public DisasterDescription getMostImpactfulYearByCategory(String category, List> records) { + Stream ddsByCategory = records.stream() + .map(DisasterDescription::new) + .filter(dd -> dd.getCategory().equals(category)); + return getMostImpactfulDisaster(ddsByCategory); + } + + public DisasterDescription getMostImpactfulDisasterByYear(String year, List> records) { + Stream ddsByYear = records.stream() + .map(DisasterDescription::new) + .filter(dd -> !dd.getCategory().equals("All natural disasters")) + .filter(dd -> dd.getYear().equals(year)); + return getMostImpactfulDisaster(ddsByYear); + } + + public DisasterDescription getTotalReportedIncidentsByCategory(String category, List> records) { + int totalReportedIncidents = records.stream() + .map(DisasterDescription::new) + .filter(dd -> dd.getCategory().equals(category)) + .mapToInt(DisasterDescription::getReportedIncidentsNum) + .sum(); + return new DisasterDescription(category, "", "", totalReportedIncidents); + } - public DisasterDescription getTotalReportedIncidentsByCategory(String category, List> records) { - // TODO implement this method - return null; - } - /** * This method will return the count if the number of incident falls within the provided range. * To simplify the problem, we assume: @@ -47,12 +77,24 @@ public DisasterDescription getTotalReportedIncidentsByCategory(String category, * + If a max value is provided, then a max value is also needed. */ public int countImpactfulYearsWithReportedIncidentsWithinRange(List> records, int min, int max) { - // TODO implement this method - return -1; + return (int) records.stream() + .map(DisasterDescription::new) + .filter(disaster -> { + int incidents = disaster.getReportedIncidentsNum(); + return (min <= incidents) && (max == -1 || incidents <= max); + }).count(); } + + private int countReportedIncidents(List> records) { + return records.stream() + .map(DisasterDescription::new) + .mapToInt(DisasterDescription::getReportedIncidentsNum) + .sum(); + } public boolean firstRecordsHaveMoreReportedIndicents(List> records1, List> records2) { - // TODO implement this method - return false; + int incidents1 = countReportedIncidents(records1); + int incidents2 = countReportedIncidents(records2); + return incidents1 > incidents2; } } diff --git a/src/main/java/codingcompetition2019/DisasterDescription.java b/src/main/java/codingcompetition2019/DisasterDescription.java index 662626b..e17e2ac 100644 --- a/src/main/java/codingcompetition2019/DisasterDescription.java +++ b/src/main/java/codingcompetition2019/DisasterDescription.java @@ -1,5 +1,37 @@ package codingcompetition2019; +import java.util.List; + public class DisasterDescription { - // TODO finish this class + private String category; + private String countryCode; + private String year; + private int numIncidents; + + public DisasterDescription(String category, String countryCode, String year, int numIncidents) { + this.category = category; + this.countryCode = countryCode; + this.year = year; + this.numIncidents = numIncidents; + } + + public DisasterDescription(List csvRow) { + this(csvRow.get(0), csvRow.get(1), csvRow.get(2), Integer.parseInt(csvRow.get(3))); + } + + public String getCategory() { + return this.category; + } + + public String getCountryCode() { + return this.countryCode; + } + + public String getYear() { + return this.year; + } + + public int getReportedIncidentsNum() { + return this.numIncidents; + } } diff --git a/src/main/java/codingcompetition2019/webui/Main.java b/src/main/java/codingcompetition2019/webui/Main.java new file mode 100644 index 0000000..c51b77f --- /dev/null +++ b/src/main/java/codingcompetition2019/webui/Main.java @@ -0,0 +1,51 @@ +package codingcompetition2019.webui; + +import codingcompetition2019.CodingCompCSVUtil; +import codingcompetition2019.DisasterDescription; +import com.google.gson.Gson; + +import java.io.IOException; +import java.util.List; +import java.util.stream.Collectors; + +import static spark.Spark.*; +public class Main { + private static final String naturalDisasterByTypeFile = "src/main/resources/natural-disasters-by-type.csv"; + private static final String significantEarthquakeFile = "src/main/resources/significant-earthquakes.csv"; + private static final String significantVolanicEruptionsFile = "src/main/resources/significant-volcanic-eruptions.csv"; + + public static String loadJson(String fileName) throws IOException { + Gson gson = new Gson(); + CodingCompCSVUtil util = new CodingCompCSVUtil(); + List> records = util.readCSVFileWithoutHeaders(fileName); + List dds = records.stream().map(DisasterDescription::new).collect(Collectors.toList()); + return gson.toJson(dds); + } + + public static void main(String[] args) throws IOException { + String typeJson = loadJson(naturalDisasterByTypeFile); + String earthquakeJson = loadJson(significantEarthquakeFile); + String volcanoJson = loadJson(significantVolanicEruptionsFile); + + + System.out.println("Running on: http://localhost:4567"); + + staticFiles.location("html"); + //staticFiles.externalLocation("/home/hsheth/data/projects/2019-StateFarm-CodingCompetitionProblem-Private/src/main/resources/html"); + get("/api/disasters_by_type", (req, res) -> { + res.type("application/json"); + return typeJson; + }); + + get("/api/significant_earthquakes", (req, res) -> { + res.type("application/json"); + return earthquakeJson; + }); + + get("/api/significant_volcanic_eruptions", (req, res) -> { + res.type("application/json"); + return volcanoJson; + }); + } + +} diff --git a/src/main/resources/html/index.html b/src/main/resources/html/index.html new file mode 100644 index 0000000..f6fb346 --- /dev/null +++ b/src/main/resources/html/index.html @@ -0,0 +1,275 @@ + + + + + State Farm Natural Disaster Viewer + + + + + + + + + +
+

State Farm Natural Disaster Viewer

+

We have three interactive charts available:

+ +

Natural Disasters by Type

+

+ With this visualization, we can see the total number of natural disasters + that occur each year, broken down by type. By clicking on the labels within + the legend, you can add and remove natural disaster types from the + visualization. +

+ + +

Significant Earthquakes by Country

+ + + +

Significant Volcanic Eruptions by Country

+ + +
+ + + + + \ No newline at end of file