Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

class SubscriptionYear You are to write a class called SubscriptionYear that con

ID: 3858364 • Letter: C

Question

class SubscriptionYear

You are to write a class called SubscriptionYear that contains the following attributes and methods.

Attributes:

Instance variable called year of type int , which stores the year for a subscription data.

Instance variable called subscriptions of type double, which stores the number of subscriptions for a specific year.

all instance variables must be private.

Methods:

A constructor that takes in the year and number of subscriptions

Getter and setter method for instance variable year.

Getter and setter method for instance variable subscriptions.

A toString() method which returns only the number of subscriptions.

class Country

You are to write a class called Country that contains the following attributes and methods.

Attributes:

Instance variable called name of type String, which stores the name of the country.

Instance variable called subscriptions, a one-dimensional array of type SubscriptionYear, which holds all the subscription data for that country.

Methods:

A constructor that takes in the country name and number of years.

We will use this to initialize the size of our subscriptions array.

addSubscriptionYear() method which takes in the year of type int and a single subscription of type double. Use this to create a new SubscriptionYear object and save it in “subscriptions” array.

getNumSubscriptionsForPeriod() method which takes in two parameters of type int for the start and end year and returns a type double for the total number of subscriptions between start and end years. Throw an IllegalArgumentException (Links to an external site.)Links to an external site. if:

both dates are out of range of the data, or

dates are in inverted order, or

the given year does not cover any valid period.

NOTE: If the client requests an invalid start or an invalid end year, only return the total for the range within the requested year that is valid. For example, assume the following is client's request

However, the valid year range stored in the subscriptions array is between 2005 and 2014. Then, we will ignore all years between 1890 and 2005.

toString() method which returns a representation of the country in type String.

For example:

The output example above is tab (“ ”) separated. You may format the data as you see fit as long as subscriptions follow year and it is readable.

==============================

CSVReader.java class

package cellularData;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.net.URISyntaxException;

import java.net.URL;

import java.util.Scanner;

public class CSVReader {

   private String [] countryNames;

private int [] yearLabels;

private double [][] parsedTable;

   public CSVReader(String filename) {

       try {

           Scanner infile = new Scanner(new File(filename));

           String line = infile.nextLine().trim();

//read the line having number of countries

           while(infile.hasNextLine())

           {

               line = infile.nextLine();

               if(line.startsWith("Number of countries,"))

                   break;

           }

           if(!line.startsWith("Number of countries,"))

{

   System.out.println("Expecting a line to be Number of Countries");

   System.exit(1);

}

           String tokens[] = line.split(",");

           int numCountries = Integer.parseInt(tokens[1].trim());

           countryNames = new String[numCountries];

           //get the line with column names

           line = infile.nextLine();

           tokens = line.split(",");

           yearLabels = new int[tokens.length - 1];

           for(int i = 0; i < yearLabels.length; i++)

               yearLabels[i] = Integer.parseInt(tokens[i+1].trim());

           parsedTable = new double[numCountries][yearLabels.length];   

           //read lines for each country

           int i = 0, j;

           while(infile.hasNextLine())

           {

               line = infile.nextLine().trim();

               if(line.equals("")) continue;

               Scanner lineScanner = new Scanner(line);

               lineScanner.useDelimiter(",");

               countryNames[i] = lineScanner.next().trim();

               if(countryNames[i].charAt(0) == '"')

                   countryNames[i] +=", " + lineScanner.next().trim();

               j = 0;

               while(lineScanner.hasNextDouble())

               {

                   parsedTable[i][j] = lineScanner.nextDouble();

                   j++;

               }

               i++;

           }

             

           infile.close();

       } catch (FileNotFoundException e) {

           System.out.println(e.getMessage());

           File f = new File(".");

           System.out.println(f.getAbsolutePath());

           System.exit(1);

       }

      

   }

   public int[] getYearLabels() {

       return yearLabels;

   }

   public String[] getCountryNames() {

       return countryNames;

   }

   public double[][] getParsedTable() {

       return parsedTable;

   }

   public int getNumberOfYears() {

       return yearLabels.length;

   }

}

===========================

cellular.csv

====================================

cellular_short_oneDecade.csv

Explanation / Answer

Edit the file path accordingly
---------------------------------------
TestCountry.java
--------------------------------
/**
* Tests the Country class by creating multiple objects.
* Creates one object of type CSVReader class, which reads input from a CSV file. Uses
* the attributes stored in CSVReader object to create objects of type Country class.
*
*/
public class TestCountry
{
    /**
     * Displays the names of countries.
     * Each country index is output along with the country's index in the array.
     * @param countryList   array of Country objects
     */
    private void displayCountryNames(Country [] countries)
    {
        String countryNames = "";
        int counter = 0;

        for (int i = 0; i < countries.length; i++)
        {
            // Concatenates the name of countries.
            countryNames += " " + countries[i].getName();

            // uses a ternary operator to prettify the output
            countryNames += (counter+1) % 5 == 0 ? " " : ",";

            counter++;
        }

        System.out.println(" Country Names:" + countryNames + " ");
    }


    /**
     * Includes test examples for class Country.
     */
    public static void main(String[] args)
    {
        // Create and set objects of type Country
        //
        final String FILENAME = "resources/cellular.txt"; // Directory path for Mac OS X
        //final String FILENAME = "resources\cellular.csv"; // Directory path for Windows OS (i.e. Operating System)
        final int NUM_COUNTRIES_TO_TEST = 3;         // Note: Include test cases in addition to 3


        // Parses the CSV data file
        // NOTE: Handle all exceptions in the constructor.
        //       For full credit, do *not* throw exceptions to main.
        CSVReader parser = new CSVReader(FILENAME);

        // In class CSVReader the accessor methods only return values of instance variables.
        String [] countryNames = parser.getCountryNames();
        int [] yearLabels = parser.getYearLabels();
        double [][] parsedTable = parser.getParsedTable();


        // TODO: Create the class Country to hold the data for one country
        Country [] countries;
        //countries = new Country[NUM_COUNTRIES_TO_TEST]; // Note: Use this for initial testing of your implementation.

        // An array of Country objects.
        // NOTE: Here, we are no longer using a 2D array of CellularData class.
        //       Instead, each country will hold it's own cellular data.
        //       So, we no longer need the CellularData class.
        countries = new Country[countryNames.length];

        // Reference to a Country object
        Country current;

        // Go through each country name parsed from the CSV file.
        for (int countryIndex = 0; countryIndex < countries.length; countryIndex++)
        {
            int numberOfYears = yearLabels.length;   // OR numberOfYears = dataTable[countryIndex].length;

            // Create a Country object
            // TODO: Create a class constructor which takes two arguments:
            //       1) a String for the name of the country
            //       2) an integer for the number of cellular data for each country
            // NOTE: Similar to the previous project we'll assume the data is well formed
            //       with the same number of years of cellular data for all countries.
            current = new Country(countryNames[countryIndex], numberOfYears);

            // Go through each year of cellular data read from the CSV file.
            for (int yearIndex = 0; yearIndex < numberOfYears - 1; yearIndex++)
            {
                double [] allSubscriptions = parsedTable[countryIndex];
                double countryData = allSubscriptions[yearIndex];

                // TODO: Create the class SubscriptionYear to hold two the data
                //       for one cellular year:
                //       1) an integer for the year
                //       2) a double for the subscriptions for that year
                current.addSubscriptionYear(yearLabels[yearIndex], countryData);
            }

            // add the newly created country to the 1D array
            countries[countryIndex] = current;
        }


        TestCountry application = new TestCountry();

        // Displays the name of each Country object
        application.displayCountryNames(countries);
        // Given the cellular_short_oneDecade.csv file, the output is:
        // Country Names: Bangladesh, Brazil, Germany,


        // Tests finding a country and retrieving subscriptions between a requested period
        //
        double totalSubscriptions;
        try
        {
            totalSubscriptions = countries[0].getNumSubscriptionsForPeriod(1960,2014);
            System.out.printf("%s (1960 to 2014): %.2f ", countryNames[0], totalSubscriptions);
        }
        catch (IllegalArgumentException ex)
        {
            System.out.println(ex.getMessage());
        }
        // Given the full cellular.csv file, the output is:
        // Afghanistan (1960 to 2014): 420.07

        try
        {
            totalSubscriptions = countries[100].getNumSubscriptionsForPeriod(1950,2014);
            System.out.printf("%s (1950 to 2014): %.2f ", countryNames[100], totalSubscriptions);
        }
        catch (IllegalArgumentException ex)
        {
            System.out.println(ex.getMessage());
        }
        // Given the full cellular.csv file, the output is:
        // Illegal Argument Request of start year 1950. Valid period for Hong Kong SAR, China is 1960 to 2015.

        try
        {
            totalSubscriptions = countries[200].getNumSubscriptionsForPeriod(1980,2014);
            System.out.printf("%s (1980 to 2014): %.2f ", countryNames[200], totalSubscriptions);
        }
        catch (IllegalArgumentException ex)
        {
            System.out.println(ex.getMessage());
        }
        // Given the full cellular.csv file, the output is:
        //
        // Rwanda (1980 to 2014): 296.41


        // TODO: For full credit, include test cases in addition to those provided.
        //
        // TODO: Also, make sure to test for other invalid requests for range of years.
        //
    }
}
----------------------------------------------------------------------
Country.java
------------------------------
public class Country
{
    private String name;
    private SubscriptionYear[] subscriptions;
    private int numYears;
    private int subscriptionPosition = 0;

    public static int MIN_YEARS = 0;
    public static int DEFAULT_YEARS = 54;


    public Country(String countryName, int numYearsC)
    {
        name = countryName;
        if (setSubscriptions(numYearsC) == false)
        {
            setSubscriptions(DEFAULT_YEARS);
        }
        subscriptions = new SubscriptionYear[numYears];
    }

    public boolean setSubscriptions (int yearIn)
    {
        if (yearIn < MIN_YEARS)
        {
            System.out.println("Not a valid number of years.");
            return false;
        }
        else
        {
            numYears = yearIn;
            return true;
        }
    }

    public String getName()
    {
        return name;
    }

    public void addSubscriptionYear (int currentYear, double currentSubscriptions)
    {
        SubscriptionYear thisYear = new SubscriptionYear (currentYear, currentSubscriptions);
        if (subscriptionPosition < numYears)
        {
            subscriptions [subscriptionPosition] = thisYear;
            subscriptionPosition++;
        }
        else
        {
            System.out.println("Exceeded parameter number of years.");
        }
    }

    public double getNumSubscriptionsForPeriod(int startYear, int endYear)
    {
        double totalSubscriptions = 0;
        if (startYear < 1960)
        {
            startYear = 1960;
        }
        else if (endYear > 2014)
        {
            endYear = 2014;
        }
        for (int i = 0; i < subscriptions.length; i++)
        {
            if (subscriptions[i] != null)
            {
                if (subscriptions[i].getYear() <= endYear && subscriptions[i].getYear() >= startYear)
                {
                    totalSubscriptions = totalSubscriptions + subscriptions[i].getSubscriptions();
                }
            }
        }
        return totalSubscriptions;
    }

    public String toString()
    {
        String countryString = "";
        countryString = countryString + name + " ";
        for (int i = 0; i < subscriptions.length; i++)
        {
            countryString = countryString + subscriptions[i] + " ";
        }
        return countryString;
    }
}
------------------------------------------------------------------------
CSVReader.java
----------------------------
/**
* CSVReader class, converts a csv file to a usable double array.
*
*/
import java.io.File;
import java.util.Scanner;

public class CSVReader {

    private String [] linesOfText;
    private String [][] cellularDataTable;
    private int [] yearLabels;
    private int numYears;
    private int numLines;
    private String [] countryNames;

    /**
     * Constructor for CSVReader
     * @param fileLocation
     * String for file location
     * @param numLines1
     * Integer for the number of lines
     */
    CSVReader(String fileLocation)
    {
        //numLines = numLines1;
        numLines = findNumLines(fileLocation);
        linesOfText = new String[numLines];
        countryNames = new String [numLines - 3];
        int count = 0;
        try {
            File file = new File(fileLocation);

            Scanner input = new Scanner(file);

            while (input.hasNextLine() && count < linesOfText.length) {
                String line = input.nextLine();
                linesOfText[count] = line;
                count++;
            }
            input.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        //int numYears = getNumYears(linesOfText);
        //System.out.println(numYears);
        numYears = findNumYears (linesOfText);
        cellularDataTable = separateByTokens(linesOfText, numYears);
        yearLabels = new int[numYears];
        yearLabels = findYearLabels(linesOfText);
        countryNames = findCountryNames(cellularDataTable, numLines);
    }

    /**
     * Returns an integer for the total number of years, found through textLines
     * @param textLines
     * String for lines of text
     * @return number of years
     * An integer for number of years
     */
    int findNumYears (String[] textLines)
    {
        int years = 0;
        for (int i = 0; i < textLines.length; i++)
        {
            String [] tokens = textLines[i].split(",");
            if (tokens [0].equals("Country Name"))
            {
                years = tokens.length;
            }
        }
        return years;
    }

    /**
     * Returns a 2D array, of textLines separated by commas
     * @param textLines
     * String array of lines of text
     * @param numYears
     * Integer for number of years
     * @return
     * Returns a 2D string array
     */
    String[][] separateByTokens(String[] textLines, int numYears)
    {
        String [][] allTokens;
        allTokens = new String [textLines.length][numYears];
        for (int i = 1; i < textLines.length; i++)
        {
            String [] tokens = textLines[i].split(",");
            if (tokens[0].charAt(0) == '"')
            {
                tokens [0] = tokens [0] + tokens [1];
                for (int l = 1; l < tokens.length - 1; l ++)
                {
                    tokens [l] = tokens [l+1];
                }
            }
            for (int j = 0; j < tokens.length; j++)
            {
                if (i < textLines.length && j < numYears)
                {
                    allTokens[i][j] = tokens[j];
                }
            }
        }
        return allTokens;
    }
    /**
     * Accessor for numYears
     * @return
     * Returns # years
     */
    int getNumberOfYears()
    {
        return numYears;
    }

    /**
     * Finds a 1D array of ints for year labels from textLines
     * @param textLines
     * String array for lines of text
     * @return
     * Returns the year labels
     */

    int[] findYearLabels (String[] textLines)
    {
        int years = 0;
        int startingYear = 0;
        int[] yearLabelsGetter;
        for (int i = 0; i < textLines.length; i++)
        {
            String [] tokens = textLines[i].split(",");
            if (tokens [0].equals("Country Name"))
            {
                years = tokens.length;
                startingYear = Integer.parseInt(tokens[1]);
            }
        }
        yearLabelsGetter = new int[years];
        for (int i = 0; i < years - 1; i++)
        {
            yearLabelsGetter[i] = startingYear + i;
        }
        return yearLabelsGetter;
    }

    /**
     * Finds and returns a 1D array for country names
     * @param data
     * 2D String array
     * @param numLines1
     * Integer number of lines
     * @return
     * Returns a 1d string array for country names
     */

    String [] findCountryNames(String[][] data, int numLines1)
    {
        String [] countriesHolder;
        int numCountries = numLines1 - 3;
        countriesHolder = new String [numCountries];
        for (int i = 0; i < numCountries; i++)
        {
            countriesHolder[i] = data[i + 3][0];
        }
        return countriesHolder;
    }

    /**
     * Returns countryNames
     * @return
     * 1D String array country names
     */

    String [] getCountryNames()
    {
        return countryNames;
    }

    /**
     * Returns yearLabels
     * @return
     * Year labels 1d int array
     */

    int [] getYearLabels()
    {
        return yearLabels;
    }

    /**
     * accessor for number of lines
     * @return
     * Integer for number of lines
     */
    int getNumLines()
    {
        return numLines;
    }

    /**
     * returns a parsed table
     * @return
     * 2D double array for the parsed table
     */
    double [][] getParsedTable()
    {
        double [][] parsingTable;
        int numLinesN = numLines - 3;
        parsingTable = new double [numLines - 3][numYears - 1];
        for (int i = 0; i < numLinesN; i ++)
        {
            for (int j = 0; j < numYears - 1; j++)
            {
                parsingTable[i][j] = Double.parseDouble(cellularDataTable[i + 3][j + 1]);
            }
        }
        return parsingTable;
    }

    int findNumLines (String fileLocation)
    {
        int count = 0;
        try {
            File file = new File(fileLocation);

            Scanner input = new Scanner(file);

            while (input.hasNextLine()) {
                input.nextLine();
                count++;
            }
            input.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return count;
    }

}
--------------------------------------------------------------
SubscriptionYear.java
----------------------------
public class SubscriptionYear
{
    private int year;
    private double subscriptions;

    public static int MIN_YEAR = 1960;
    public static int MAX_YEAR = 2014;
    public static int DEFAULT_YEAR = 1997;
    public static int MIN_SUBSCRIPTIONS = 0;
    public static int DEFAULT_SUBSCRIPTIONS = 0;

    public SubscriptionYear(int yearC, double subscriptionsC)
    {
        if (setYear(yearC) == false)
        {
            setYear(DEFAULT_YEAR);
        }

        if (setSubscriptions(subscriptionsC) == false)
        {
            setSubscriptions(DEFAULT_SUBSCRIPTIONS);
        }
    }

    public boolean setYear (int yearIn)
    {
        if (yearIn < MIN_YEAR || yearIn > MAX_YEAR)
        {
            System.out.println("Not a valid year.");
            return false;
        }
        else
        {
            year = yearIn;
            return true;
        }
    }

    public int getYear()
    {
        return year;
    }

    public boolean setSubscriptions (double subscriptionsIn)
    {
        if (subscriptionsIn < MIN_SUBSCRIPTIONS)
        {
            System.out.println("Not a valid # of subscriptions.");
            return false;
        }
        else
        {
            subscriptions = subscriptionsIn;
            return true;
        }
    }

    public double getSubscriptions()
    {
        return subscriptions;
    }

    public String toString()
    {
        String subscriptionsString = "subscriptions";
        return subscriptionsString;
    }
}
---------------------------------------------------------------------
CellularData.java
-------------------------------
public class CellularData
{
    private int numCountries;
    private int numSubscriptions;
    private int startingYear;
    private Double [][] table;
    private String [] countryNames;
    private int countryNumber = 0;
    private int [] year;
    String subscriptionString;
    private int endingYear;

    /**
     * Constructor with 3 parameters
     * @param numCountries
     * integer number of countries
     * @param numSubscriptions
     * integer number of subscriptions
     * @param startingYear
     * integer starting year
     */
    public CellularData (int numCountries, int numSubscriptions, int startingYear)
    {
        //Set values to parameters
        this.numCountries = numCountries;
        this.numSubscriptions = numSubscriptions;
        this.startingYear = startingYear;
        endingYear = startingYear + numSubscriptions - 1;

        table = new Double[numCountries][numSubscriptions]; //Create a table
        for (int i=0; i < numCountries; i++) //numCountries x numSubscriptions
        {
            for (int j=0; j < numSubscriptions; j++)
            {
                table[i][j] = null;
            }
        }

        //Creates an array for years
        year = new int [numSubscriptions];
        for (int i = 0; i < numSubscriptions; i++)
        {
            year [i] = startingYear + i;
        }


        //Creates an array for the names of countries by their corresponding number
        countryNames = new String [numCountries];
        for (int i = 0; i < numCountries; i++)
        {
            countryNames [i] = null;
        }
    }

    /**
     * Function to add a country, taking 2 parameters
     * @param countryName
     * Parameter string country name
     * @param subscriptions
     * parameter double array of subscriptions
     */
    public void addCountry(String countryName, double [] subscriptions)
    {
        if (countryNumber < numCountries)
        {
            countryNames [countryNumber] = countryName;
            for (int i = 0; i < subscriptions.length; i ++)
            {
                table [countryNumber][i] = subscriptions [i];
            }
            countryNumber++;
        }
    }

    /**
     * Converts the subscriptions of a country to a string
     * @param country
     * A string for the country
     * @return
     * Returns a String for the subscriptions for a country
     */

    public String toString(int country)
    {
        if (country >= 0 && country < numCountries)
        {
            subscriptionString = "";
            for (int i = 0; i < numSubscriptions; i++)
            {
                subscriptionString = subscriptionString + this.table[country][i] + ",";
            }
            return subscriptionString;
        }
        String error = "invalid country";
        return error;
    }

    public String toString()
    {
        String toStringString = "";
        toStringString = toStringString + "Country Year ";
        for (int i = 0; i < endingYear + 1 - startingYear; i++)
        {
            toStringString = toStringString + year[i] + " ";
        }
        for (int i = 0; i < numCountries; i++)
        {
            toStringString = toStringString + " " + countryNames[i] + " ";
            toStringString = toStringString + toString(i);
        }
        toStringString = toStringString + " ";
        return toStringString;
    }

    /**
     * Returns a value for the number of subscriptions for a country during a period
     * @param countryName
     * String country name
     * @param startYear
     * integer starting year
     * @param endYear
     * integer ending year
     * @return
     * Returns a double for the number of subscriptions in a country during a period
     */

    public double getNumSubscriptionsInCountryForPeriod(String countryName,int startYear,int endYear)
    {
        int countryNumber = -1;
        double totalNumber = 0;
        //Check which country this is
        for (int i = 0; i < numCountries; i++)
        {
            if (countryNames [i] == countryName)
            {
                countryNumber = i;
            }
        }
        if (countryNumber == -1)
        {
            System.out.println("Not a valid country!");
            return 1000;
        }
        //If the country is not found, return 1000 (an arbitrary value for error)
        if (countryNumber == -1 || startYear < startingYear || endYear > endingYear)
        {
            System.out.println("Not a valid year!");
            totalNumber = 1000;
            return totalNumber;
        }
        //If found, then total up all of the years and return the value
        for (int i = startYear - startingYear; i < endYear + 1 - startingYear; i++)
        {
            totalNumber = totalNumber + this.table[countryNumber][i];
        }
        return totalNumber;
    }

    /**
     * Prints a table
     */
    public void printTable()
    {
      /*
      Testing with Partial Data:
      Country Year 1983 1984 1985 1986 1987 1988 1989
      Canada         0 0 0.04 0.22 0.37 0.75 1.26
      Mexico         0 0 0 0 0 -0.00 0.01
      United States     0 0.03 0.14 0.27 0.49 0.82 1.39
       */
        System.out.print("Country Year ");
        for (int i = 0; i < endingYear + 1 - startingYear; i++)
        {
            System.out.print(year[i] + " ");
        }
        for (int i = 0; i < numCountries; i++)
        {
            System.out.print(" " + countryNames[i] + " ");
            System.out.print(toString(i));
        }
        System.out.print(" ");
    }
}