diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..92322c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +target/ diff --git a/feedback.txt b/feedback.txt index 8234592..568dd8e 100644 --- a/feedback.txt +++ b/feedback.txt @@ -1,9 +1,9 @@ -Your team (name of each individual participating): -How many JUnits were you able to get to pass? +Your team (name of each individual participating): Kris Satya and Rishab Mitra +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: + Step 1: All methods documented with javadocs + Step 2: Added command line test that can be executed by running main method of DisasterCLI Feedback for the coding competition? Things you would like to see in future events? \ No newline at end of file diff --git a/pom.xml b/pom.xml index 78eb746..c0b19d6 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 + + 7 + 7 + + + + + jar codingcompetition2019 http://maven.apache.org diff --git a/src/main/java/codingcompetition2019/CodingCompCSVUtil.java b/src/main/java/codingcompetition2019/CodingCompCSVUtil.java index 74f3074..58cc204 100644 --- a/src/main/java/codingcompetition2019/CodingCompCSVUtil.java +++ b/src/main/java/codingcompetition2019/CodingCompCSVUtil.java @@ -1,42 +1,105 @@ package codingcompetition2019; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; + public class CodingCompCSVUtil { + private final String ALL_CATEGORIES = "ALL"; + private final String COMMA_DELIMITER = ","; + private final String SKIP_HEADER = "SKIP_HEADER"; + private final String ALL_DISASTERS = "All natural disasters"; + private final int ENTITY_COLMN = 0; + private final int YEAR_COLMN = 2; + private final int INCIDENTS_COLMN = 3; + + /** + * Returns a list of all the records parsed by country + * @param fileName the csv filename + * @param countryName the country + * @return the list of all records + * @throws IOException if file is not found + */ public List> readCSVFileByCountry(String fileName, String countryName) throws IOException { - // TODO implement this method - return null; + return helperReadCSVFile(fileName, countryName); } - + + /** + * Returns a list of all the records with the first header line + * @param fileName the csv filename + * @return the list of all the records + * @throws IOException if file is not found + */ public List> readCSVFileWithHeaders(String fileName) throws IOException { - // TODO implement this method - return null; + return helperReadCSVFile(fileName, ALL_CATEGORIES); } - + + /** + * Returns a list of all the records without the first header line + * @param fileName the csv filename + * @return the list of all the records + * @throws IOException if file is not found + */ public List> readCSVFileWithoutHeaders(String fileName) throws IOException { - // TODO implement this method - return null; + return helperReadCSVFile(fileName, SKIP_HEADER); } - + + /** + * Returns a disaster description containing the most impactful year + * @param records the records from the csv file + * @return the disaster description with the most impactful year + */ public DisasterDescription getMostImpactfulYear(List> records) { - // TODO implement this method - return null; + return helperGetMostImpactfulYear(ALL_CATEGORIES, records); } + /** + * Returns a disaster description containing the most impactful year by category + * @param category the category of the record + * @param records the records from the csv file + * @return the disaster description with the most impactful year by category + */ public DisasterDescription getMostImpactfulYearByCategory(String category, List> records) { - // TODO implement this method - return null; + return helperGetMostImpactfulYear(category, records); } + /** + * Returns the most impactful disaster for the specified year. + * @param year the specified year + * @param records the records from the csv file + * @return the disaster description with the most impactful year + */ public DisasterDescription getMostImpactfulDisasterByYear(String year, List> records) { - // TODO implement this method - return null; + String maxCategory = null; + int maxDisaster = 0; + for (List record : records) { + if (!getLineEntity(record).equals(ALL_DISASTERS)) { + if (getLineYear(record).equals(year)) { + String category = getLineEntity(record); + int numDisasters = Integer.parseInt(getNumIncidents(record)); + if (numDisasters > maxDisaster) { + maxDisaster = numDisasters; + maxCategory = category; + } + } + } + } + return new DisasterDescription(year, maxCategory, maxDisaster); } + /** + * Returns the total number of incidents based on the records that match the category. + * @param category the category of records + * @param records the records from the csv file + * @return the total number of reported incidents + */ public DisasterDescription getTotalReportedIncidentsByCategory(String category, List> records) { - // TODO implement this method - return null; + return helperGetTotalReportedIncidents(category, records); } /** @@ -47,12 +110,145 @@ 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; + if (max == -1) { + max = Integer.MAX_VALUE; + } + int numYearsInRange = 0; + for (List record : records) { + if (Integer.parseInt(getNumIncidents(record)) >= min && Integer.parseInt(getNumIncidents(record)) <= max) { + numYearsInRange++; + } + } + return numYearsInRange; } - + + /** + * Determines whether the first record has more total incidents than the second record. + * @param records1 the first csv file records + * @param records2 the second csv file records + * @return true if the first csv file has more incidents or false otherwise + */ public boolean firstRecordsHaveMoreReportedIndicents(List> records1, List> records2) { - // TODO implement this method - return false; + return helperGetTotalReportedIncidents(ALL_CATEGORIES, records1).getReportedIncidentsNum() > helperGetTotalReportedIncidents(ALL_CATEGORIES, records2).getReportedIncidentsNum(); + } + + /** + * Helper method to get the total number of incidents that match the category. + * @param category the category of incidents or all categories + * @param records the records from the csv file + * @return a disaster description object containing the total reported incidents + */ + public DisasterDescription helperGetTotalReportedIncidents (String category, List> records) { + boolean allCategories = false; + if (category.equals(ALL_CATEGORIES)) { + allCategories = true; + } + DisasterDescription disaster = new DisasterDescription("N/A", category, 0); + + for (List record : records) { + + if (!allCategories && !getLineEntity(record).equals(category)) { + continue; + } + disaster.addReportedIncidents(Integer.parseInt(getNumIncidents(record))); + } + return disaster; + } + + /** + * Helper method to get the most impactful year (most number of incidents) by category. + * @param category the category of the entity in the record or all categories + * @param records the records from the csv file + * @return the disaster description containing the most impactful year + */ + public DisasterDescription helperGetMostImpactfulYear (String category, List> records) { + boolean allCategories = false; + if (category.equals(ALL_CATEGORIES)) { + allCategories = true; + } + + String mostImpactfulYear = null; + int maxYearImpact = 0; + + for (List record : records) { + if (!allCategories && !getLineEntity(record).equals(category)) { + continue; + } + + int currImpact = Integer.parseInt(getNumIncidents(record)); + if (currImpact > maxYearImpact) { + maxYearImpact = currImpact; + mostImpactfulYear = getLineYear(record); + } + } + return new DisasterDescription(mostImpactfulYear); + } + + /** + * Helper method to parse csv file based on the specified parameters. Extra parameter is ALL_CATEGORIES + * if entire csv file needs to be parsed, SKIP_HEADER if entire csv needs to be parsed without header, + * or the country name if a specific country needs to be parsed. + * + * @param fileName the csv file + * @param extraParam the extra parameter (all categories/skip header/country name) + * @return a list of all the entries in csv file matching the query + * @throws IOException if file is not found + */ + private List> helperReadCSVFile(String fileName, String extraParam) throws IOException{ + boolean allCategories = false; + boolean header = true; + if (extraParam.equals(SKIP_HEADER)) { + header = false; + allCategories = true; + } else if (extraParam.equals(ALL_CATEGORIES)) { + allCategories = true; + } + List> csvFile = new ArrayList>(); + try { + BufferedReader br = new BufferedReader(new FileReader(fileName)); + String line = ""; + while ((line = br.readLine()) != null) { + if (!header) { + header = true; + continue; + } + String[] lineData = line.split(COMMA_DELIMITER, -1); + List lineDataList = Arrays.asList(lineData); + if (!allCategories && !getLineEntity(lineDataList).equals(extraParam)) { + continue; + } + csvFile.add(lineDataList); + } + } catch(FileNotFoundException e) { + e.printStackTrace(); + } + return csvFile; + } + + /** + * Helper method returns the year from the current line in csv file. + * @param lineData current line in csv file + * @return year of current line + */ + private String getLineYear(List lineData) { + return lineData.get(YEAR_COLMN); + } + + /** + * Helper method returns the entity from the current line in csv file. + * @param lineData current line in csv file + * @return entity of current line + */ + private String getLineEntity(List lineData) { + return lineData.get(ENTITY_COLMN); + } + + /** + * Helper method returns the number of incidents from the current line in csv file. + * @param lineData current line in csv file + * @return year of current line + */ + private String getNumIncidents(List lineData) { + return lineData.get(INCIDENTS_COLMN); } } diff --git a/src/main/java/codingcompetition2019/DisasterCLI.java b/src/main/java/codingcompetition2019/DisasterCLI.java new file mode 100644 index 0000000..5f9a34b --- /dev/null +++ b/src/main/java/codingcompetition2019/DisasterCLI.java @@ -0,0 +1,107 @@ +package codingcompetition2019; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Scanner; +public class DisasterCLI { + private static CodingCompCSVUtil util = new CodingCompCSVUtil(); + private static List> records; + public static void main(String[] args) { + HashMap directions = directions(); + System.out.println("Please enter the number of which method that you want to peruse."); + System.out.println("0: getMostImpactfulYear"); + System.out.println("1: getMostImpactfulYearByCategory"); + System.out.println("2: getMostImpactfulDisasterByYear"); + System.out.println("3: getTotalReportedIncidentsByCategory"); + System.out.println("4: countImpactfulYearsWithReportedIncidentsWithinRange"); + Scanner scanner = new Scanner(System.in); + String numMethod = scanner.next(); + int method = -1; + try { + method = Integer.parseInt(numMethod); + } catch(Exception e) { + + } + if (method == 0) { + try { + System.out.println(impactfulYear()); + } catch(IOException e) { + e.printStackTrace(); + } + } else if (method == 1) { + System.out.println(directions.get(method)); + String category = scanner.next(); + try { + System.out.println(categoryImpactfulYear(category)); + } catch (IOException e) { + e.printStackTrace(); + } + } else if (method == 2) { + System.out.println(directions.get(method)); + String category = scanner.next(); + try { + System.out.println(yearImpactfulDisaster(category)); + } catch (IOException e) { + e.printStackTrace(); + } + } else if (method == 3) { + System.out.println(directions.get(method)); + String category = scanner.next(); + try { + System.out.println(totalIncidents(category)); + } catch (IOException e) { + e.printStackTrace(); + } + } else if (method == 4){ + System.out.println(directions.get(method)); + String country = scanner.next(); + int min = scanner.nextInt(); + int max = scanner.nextInt(); + try { + System.out.println(rangeIncidents(country, min, max)); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + System.out.println("Please rerun and enter proper input."); + } + + + } + + public static HashMap directions() { + HashMap directions = new HashMap(); + directions.put(1, "Please enter the category you want to look at."); + directions.put(2, "Please enter the year you want to look at."); + directions.put(3, "Please enter the category you want to look at."); + directions.put(4, " First enter a country you want to look at. Then please enter two integer " + + "values. One min and max value which represent your range. "); + return directions; + } + + public static String impactfulYear() throws IOException { + records = util.readCSVFileWithoutHeaders("src/main/resources/natural-disasters-by-type.csv"); + return util.getMostImpactfulYear(records).getYear(); + } + + public static String categoryImpactfulYear(String category) throws IOException { + records = util.readCSVFileWithoutHeaders("src/main/resources/natural-disasters-by-type.csv"); + return util.getMostImpactfulYearByCategory(category, records).getYear(); + } + + public static String yearImpactfulDisaster(String year) throws IOException { + records = util.readCSVFileWithoutHeaders("src/main/resources/natural-disasters-by-type.csv"); + return util.getMostImpactfulDisasterByYear(year, records).getCategory(); + } + + public static int totalIncidents(String category) throws IOException { + records = util.readCSVFileWithoutHeaders("src/main/resources/natural-disasters-by-type.csv"); + return util.getTotalReportedIncidentsByCategory(category, records).getReportedIncidentsNum(); + } + public static int rangeIncidents(String country, int min, int max) throws IOException { + List> tempRecords = util.readCSVFileByCountry("src/main/resources/signifi" + + "cant-volcanic-eruptions.csv", country); + return util.countImpactfulYearsWithReportedIncidentsWithinRange(tempRecords, min, max); + } +} diff --git a/src/main/java/codingcompetition2019/DisasterDescription.java b/src/main/java/codingcompetition2019/DisasterDescription.java index 662626b..57dedae 100644 --- a/src/main/java/codingcompetition2019/DisasterDescription.java +++ b/src/main/java/codingcompetition2019/DisasterDescription.java @@ -1,5 +1,59 @@ package codingcompetition2019; public class DisasterDescription { - // TODO finish this class + private String year = ""; + private String category = ""; + private int reportedIncidents = 0; + + /** + * Creates a new Disaster Description object with just a year + * @param year the year of the disaster + */ + public DisasterDescription(String year) { + this(year, "", 0); + } + + /** + * Creates a new Disaster Description object with specified parameters + * @param year year of disaster or N/A if over multiple years + * @param type the category of the disaster + * @param reportedIncidents the number of reported incidents + */ + public DisasterDescription(String year, String type, int reportedIncidents) { + this.year = year; + this.category = type; + this.reportedIncidents = reportedIncidents; + } + + /** + * Getter method for the number of reported incidents. + * @return the number of reported incidents. + */ + public int getReportedIncidentsNum() { + return reportedIncidents; + } + + /** + * Adds number of new incidents to the current number of reported incidents. + * @param numIncidents the number of incidents + */ + public void addReportedIncidents(int numIncidents) { + reportedIncidents += numIncidents; + } + + /** + * Getter method for the year + * @return the year + */ + public String getYear() { + return year; + } + + /** + * Getter method for the category + * @return the category + */ + public String getCategory() { + return category; + } } diff --git a/src/test/java/codingcompetition2019/CodingCompCSVUtilTest.java b/src/test/java/codingcompetition2019/CodingCompCSVUtilTest.java index 85ab612..6c2d47d 100644 --- a/src/test/java/codingcompetition2019/CodingCompCSVUtilTest.java +++ b/src/test/java/codingcompetition2019/CodingCompCSVUtilTest.java @@ -10,69 +10,69 @@ public class CodingCompCSVUtilTest extends TestCase { private CodingCompCSVUtil util; - + private List> records; - + private String naturalDisasterByTypeFile = "src/main/resources/natural-disasters-by-type.csv"; - + private String significantEarthquakeFileNameName = "src/main/resources/significant-earthquakes.csv"; - + private String significantVolcanicEruptionsFileName = "src/main/resources/significant-volcanic-eruptions.csv"; @Before public void setUp() throws Exception { util = new CodingCompCSVUtil(); records = util.readCSVFileWithoutHeaders(naturalDisasterByTypeFile); - } - + } + @Test public void testReadCSVFileWithHeadersByCountry() throws IOException { List> tempRecords = util.readCSVFileByCountry(significantEarthquakeFileNameName, "United States"); assertEquals(945, tempRecords.size()); - + tempRecords = util.readCSVFileByCountry(significantVolcanicEruptionsFileName, "United States"); assertEquals(343, tempRecords.size()); } - + @Test public void testGetTheMostImpactfulYearInUSAByEarthquake() throws IOException { List> earthquakeRecords = util.readCSVFileByCountry(significantEarthquakeFileNameName, "United States"); assertEquals("2011", util.getMostImpactfulYear(earthquakeRecords).getYear()); } - + @Test public void testReadCSVFileWithHeaders() throws IOException { assertEquals(829, util.readCSVFileWithHeaders(naturalDisasterByTypeFile).size()); } - + @Test public void testReadCSVFileWithoutHeaders() throws IOException { assertEquals(828, util.readCSVFileWithoutHeaders(naturalDisasterByTypeFile).size()); } - + @Test public void testGetMostImpactfulYear() { assertEquals("2005", util.getMostImpactfulYear(records).getYear()); } - + @Test public void testGetMostImpactfulYearByCategory() { assertEquals("1990", util.getMostImpactfulYearByCategory("Earthquake", records).getYear()); } - + @Test public void testGetMostImpactfulDisasterByYear() { DisasterDescription dd = util.getMostImpactfulDisasterByYear("2005", records); - + assertEquals("Flood", dd.getCategory()); assertEquals(193, dd.getReportedIncidentsNum()); } - + @Test public void testGetTotalReportedIncidentsByCategoryy() { assertEquals(1372, util.getTotalReportedIncidentsByCategory("Earthquake", records).getReportedIncidentsNum()); } - + @Test public void testCountImpactfulYearsWithReportedIncidentsWithinRange() throws IOException { List> tempRecords = util.readCSVFileByCountry(significantVolcanicEruptionsFileName, "United States"); @@ -80,7 +80,7 @@ public void testCountImpactfulYearsWithReportedIncidentsWithinRange() throws IOE assertEquals(40, util.countImpactfulYearsWithReportedIncidentsWithinRange(tempRecords, 1, -1)); assertEquals(4, util.countImpactfulYearsWithReportedIncidentsWithinRange(tempRecords, 2, 4)); } - + @Test public void testFirstRecordsHaveMoreReportedIndicents() throws IOException { List> tempRecords1 = util.readCSVFileByCountry(significantEarthquakeFileNameName, "United States"); @@ -89,4 +89,4 @@ public void testFirstRecordsHaveMoreReportedIndicents() throws IOException { assertTrue(util.firstRecordsHaveMoreReportedIndicents(tempRecords1, tempRecords2)); assertFalse(util.firstRecordsHaveMoreReportedIndicents(tempRecords2, tempRecords1)); } -} +} \ No newline at end of file