Skip to content

Instantly share code, notes, and snippets.

@thegabriele97
Created May 11, 2018 16:42
Show Gist options
  • Save thegabriele97/61666c04d6fd82400d25e96ade1ca6fd to your computer and use it in GitHub Desktop.
Save thegabriele97/61666c04d6fd82400d25e96ade1ca6fd to your computer and use it in GitHub Desktop.
package schools;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//import static java.util.Comparator.*;
/**
* Represents the region and serves as a facade class
* for the package.
*
* It provides factory methods for creating instances of
* {@link Community}, {@link Municipality}, {@link School}, and {@link Branch}
*
*/
public class Region {
private static final int FIELD_PROVINCE = 0;
private static final int FIELD_MUNI = 1;
private static final int FIELD_GRADE = 2;
private static final int FIELD_DESCRIPTION = 3;
private static final int FIELD_COD_BRANCH = 4;
private static final int FIELD_COD_SCHOOl = 5;
private static final int FIELD_SCHOOL_NAME = 6;
private static final int FIELD_ADDRESS = 7;
private static final int FIELD_CAP = 8;
private static final int FIELD_COMMUNITY_HILL = 9;
private static final int FIELD_COMMUNITY_MOUNT = 10;
private String name;
private Map<String, Community> listOfCommunity;
private Map<String, Municipality> listOfMunicipality;
private Map<String, School> listOfSchool;
private Map<Integer, Branch> listOfBranch;
/**
* Creates a new region with the given name.
* @param name the name of the region
*/
public Region(String name){
this.name = name;
this.listOfCommunity = new HashMap<>();
this.listOfMunicipality = new HashMap<>();
this.listOfSchool = new HashMap<>();
this.listOfBranch = new HashMap<>();
}
/**
* Getter method
* @return the name of the region
*/
public String getName(){
return name;
}
/**
* Retrieves all schools in the region
* @return collection of schools
*/
public Collection<School> getSchools() {
return listOfSchool.values();
}
/**
* Retrieves all the communities
* @return the collection of all communities
*/
public Collection<Community> getCommunities() {
return listOfCommunity.values();
}
/**
* Retrieves all municipalities in the region
* @return the collection of municipalities
*/
public Collection<Municipality> getMunicipalies() {
return listOfMunicipality.values();
}
// factory methods
/**
* Factory method that build a new community of the given type.
* The type is {@link Community.Type}
*
* @param name name of the community
* @param type type of the community
* @return the new created community
*/
public Community newCommunity(String name, Community.Type type){
Community comm = new Community(name, type);
listOfCommunity.put(comm.getName(), comm);
return comm;
}
/**
* Factory method that build a new municipality.
*
* @param nome name of the municipality
* @param province province of the municipality
* @return the new created municipality
*/
public Municipality newMunicipality(String nome, String province){
return newMunicipality(nome, province, null);
}
/**
* Factory methods, that build a new municipality that
* is part of a community.
*
* @param nome name of the municipality
* @param province province of the municipality
* @param comunita community the municipality belongs to
* @return the new created municipality
*/
public Municipality newMunicipality(String nome, String province, Community comunita){
Municipality municipality = new Municipality(nome, province, comunita);
listOfMunicipality.put(municipality.getName() + municipality.getProvince(), municipality);
return municipality;
}
/**
* Factory method that creates a new school
*
* @param name name of the school
* @param code code of the school
* @param grade grade of the school (1 to 4)
* @param description description of the school
*
* @return a new school object
*/
public School newSchool(String name, String code, int grade, String description){
School sc = listOfSchool.get(code);
if (sc == null) {
sc = new School(code, name, grade, description);
listOfSchool.put(sc.getCode(), sc);
}
return sc;
}
/**
* Factory method that creates a new school branch
*
* @param regionalCode regional code of the branch
* @param municipality municipality where the branch is located
* @param address address of the branch
* @param zipCode zip code of the branch
* @param school school the branch is part of
* @return the new created branch
*/
public Branch newBranch(int regionalCode, Municipality municipality, String address, int zipCode, School school) {
Branch branch = new Branch(regionalCode, municipality, address, zipCode, school);
listOfBranch.put(branch.getCode(), branch);
return branch;
}
/**
* Load data from a file.
*
* The file must be a CSV file and it is supposed to contain the following fields:
* <ul>
* <li>{@code "Provincia"}, (province)
* <li>{@code "Comune"}, (municipality)
* <li>{@code "Grado Scolastico"}, (school grade)
* <li>{@code "Descrizione Scuola"}, (school description)
* <li>{@code "Cod Sede"}, (branch code)
* <li>{@code "Cod Scuola"}, (school code)
* <li>{@code "Denominazione Scuola"}, (name of the school)
* <li>{@code "Indirizzo e n. civico"}, (address of the branch)
* <li>{@code "C.A.P."}, (zip code of the branch)
* <li>{@code "Comunita Collinare"}, (Hill community)
* <li>{@code "Comunita Montana"}, (Mountain community)
* </ul>
*
* @param file the path of the file
*/
public void readData(String file) {
List<String> lines;
try(BufferedReader in = new BufferedReader(new FileReader(file))) {
lines = in.lines()
.skip(1)
.collect(toList());
for (String record_str : lines) {
String[] record = record_str.split(",");
boolean isLastAComa = (record_str.charAt(record_str.length() - 1) == ',');
School school = listOfSchool.get(record[FIELD_COD_SCHOOl]);
if (school == null) {
school = newSchool(record[FIELD_SCHOOL_NAME],
record[FIELD_COD_SCHOOl],
Integer.valueOf(record[FIELD_GRADE]),
record[FIELD_DESCRIPTION]);
}
boolean isCommunityAvailable = record.length > FIELD_COMMUNITY_HILL;
Community community = null;
if (isCommunityAvailable) {
Community.Type type = (!isLastAComa) ? Community.Type.MONTANA : Community.Type.COLLINARE;
int field = (type == Community.Type.COLLINARE) ? FIELD_COMMUNITY_HILL : FIELD_COMMUNITY_MOUNT;
community = listOfCommunity.get(record[field]);
if (community == null) {
community = newCommunity(record[field], type);
}
}
Municipality municipality = listOfMunicipality.get(record[FIELD_MUNI] + record[FIELD_PROVINCE]);
if (municipality == null) {
municipality = newMunicipality(record[FIELD_MUNI],
record[FIELD_PROVINCE],
community);
}
Branch branch = listOfBranch.get(Integer.valueOf(record[FIELD_COD_BRANCH]));
if (branch == null) {
branch = newBranch(Integer.valueOf(record[FIELD_COD_BRANCH]),
municipality,
record[FIELD_ADDRESS],
Integer.valueOf(record[FIELD_CAP]),
school);
}
}
} catch(IOException e) {
System.err.println(e.getMessage());
}
}
/**
* Counts how many schools there exist for each description
* @return a map of school count vs. description
*/
public Map<String,Long>countSchoolsPerDescription(){
return listOfSchool.values()
.stream()
.collect(groupingBy(School::getDescription, counting()));
}
/**
* Count how many school branches there exist for each municipality
* @return a map of branch count vs. municipality
*/
public Map<String,Long>countBranchesPerMunicipality(){
Map<Municipality, Long> map1 = listOfMunicipality.values()
.stream()
.flatMap(m -> m.getBranches().stream())
.collect(groupingBy(Branch::getMunicipality, counting()));
Map<String, Long> newM = new HashMap<>();
map1.forEach((k, v) -> newM.put(k.getName(), v));
return newM;
}
/**
* Counts the number of school branches per municipality
* and groups them by province.
* @return a map of maps the inner reports count of branches vs. municipality
* the outer reports provinces as keys
*/
public Map<String,Map<String,Long>>countBranchesPerMunicipalityPerProvince(){
return listOfMunicipality.values()
.stream()
.flatMap(m -> m.getBranches().stream())
.collect(groupingBy(b -> ((Branch)b).getMunicipality().getProvince(),
groupingBy(b -> ((Branch)b).getMunicipality().getName(), counting())));
}
/**
* returns a list of strings with format
* {@code "### - XXXXXX"}, where
* {@code ###} represents the number of schools (not branches)
* and {@code XXXXXX} represents the name of the municipality.
* If a school has more than one branch in a municipality
* it must be counted only once.
*
* @return a collection of strings with the counts
*/
public Collection<String> countSchoolsPerMunicipality(){
return listOfBranch.values()
.stream()
.collect(groupingBy(Branch::getMunicipality, counting()))
.entrySet()
.stream()
.map(e -> e.getValue() + " - " + e.getKey().getName())
.collect(toList());
}
/**
* returns a list of strings with format
* {@code "### - XXXXXX"}, where
* {@code ###} represents the number of schools (not branches)
* and {@code XXXXXX} represents the name of the community.
* They are sorted by descending number of schools.s
* The list must contain only schools having at least
* a branch in a municipality part of a community.
*
* @return a collection of strings with the counts
*/
public List<String> countSchoolsPerCommunity(){
return listOfBranch.values()
.stream()
.filter(b -> ((Branch)b).getMunicipality().getCommunity().isPresent())
.collect(groupingBy(b -> ((Branch)b).getMunicipality().getCommunity(), counting()))
.entrySet()
.stream()
.sorted(Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()))
.map(e -> e.getValue() + " - " + e.getKey().get().getName())
.collect(toList());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment