Add some city growth stats for fun.  Birmingham takes the cake for fastest decade of growth so far, at 5.75% between 1910 and 1920.

Spain is now working due to finding an exchange rate from 1940, but the closest to 1950 is 1948 so that'll need interpolation.
2 files changed, 54 insertions(+), 0 deletions(-)

M src/main/java/DBObjects/CityDB.java
M src/main/java/com/ajtjp/gearCity/Main.java
M src/main/java/DBObjects/CityDB.java +17 -0
@@ 139,7 139,16 @@ public class CityDB {
         }
     }
     
+    private Map<Integer, Map<Integer, Double>> annualizedGrowthCache = new HashMap<>();
+    
     public Double getAnnualizedPopulationGrowthRateBetweenYears(int startYear, int endYear) {
+        //Cache
+        if (annualizedGrowthCache.containsKey(startYear)) {
+            if (annualizedGrowthCache.get(startYear).containsKey(endYear)) {
+                return annualizedGrowthCache.get(startYear).get(endYear);
+            }
+        }        
+        
         DecimalFormat df = new DecimalFormat("0.00");
         if (region != null) {
             AnnualPopFigure cityBefore = this.getPopFigureNearestYear(startYear, BEFORE);

          
@@ 155,6 164,10 @@ public class CityDB {
                 if (regionBefore.getYear() != regionAfter.getYear()) {
                     double regionalGrowthRate = regionBefore.annualizedGrowthUntil(regionAfter);
                     System.out.println("  The annualized growth rate for " + this.name + "'s region of " + this.region.getName() + " between " + startYear + " and " + endYear + " is " + df.format((regionalGrowthRate - 1) * 100) + "%");
+                    if (!annualizedGrowthCache.containsKey(startYear)) {
+                        annualizedGrowthCache.put(startYear, new HashMap<Integer, Double>());
+                    }
+                    annualizedGrowthCache.get(startYear).put(endYear, regionalGrowthRate);
                     return regionalGrowthRate;
                 }
                 return 1.0;

          
@@ 162,6 175,10 @@ public class CityDB {
             else {
                 double cityGrowthRate = cityBefore.annualizedGrowthUntil(cityAfter);
                 System.out.println("  The annualized growth rate for " + this.name + " between " + startYear + " and " + endYear + " is " + df.format((cityGrowthRate - 1) * 100) + "%");
+                if (!annualizedGrowthCache.containsKey(startYear)) {
+                    annualizedGrowthCache.put(startYear, new HashMap<Integer, Double>());
+                }
+                annualizedGrowthCache.get(startYear).put(endYear, cityGrowthRate);
                 return cityGrowthRate;
             }
         }

          
M src/main/java/com/ajtjp/gearCity/Main.java +37 -0
@@ 22,10 22,13 @@ import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.nio.charset.Charset;
+import java.text.DecimalFormat;
 import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.transform.OutputKeys;

          
@@ 52,6 55,8 @@ public class Main {
     
     final static int[] years = { 1900, 1910, 1920, 1930 };
     
+    private static DecimalFormat percentFormat = new DecimalFormat("0.00");
+    
     public static void main(String[] args) throws Exception {
 //        testXMLExport();
         Logger.getRootLogger().setLevel(Level.INFO);

          
@@ 117,6 122,8 @@ cityDBLoop: for (CityDB city : cities) {
                 cityDB.getCityList().add(xmlCity);
             }
 
+            printCityGrowthStats(cities, year);
+
             //Export back to file
             Document document= BeanToXMLUtil.convertBeanToXML(cityDB);
             TransformerFactory transformerFactory = TransformerFactory.newInstance();

          
@@ 148,6 155,36 @@ cityDBLoop: for (CityDB city : cities) {
         }
     }
 
+    static void printCityGrowthStats(List<CityDB> cities, int year) {
+        List<CityDB> fastestGrowingCities = (List<CityDB>)cities.stream().sorted(new Comparator() {
+            @Override
+            public int compare(Object o1, Object o2) {
+                CityDB city1 = (CityDB) o1;
+                CityDB city2 = (CityDB) o2;
+                return city2.getAnnualizedPopulationGrowthRateBetweenYears(year, year + 10) - city1.getAnnualizedPopulationGrowthRateBetweenYears(year, year + 10) > 0.0 ? 1 : -1;
+            }
+        }).limit(5).collect(Collectors.toList());
+        
+        System.out.println("The fastest growing cities between " + year + " and " + (year + 10) + " are");
+        for (CityDB fastCity : fastestGrowingCities) {
+            System.out.println(fastCity.getName() + "(" + percentFormat.format((100 * fastCity.getAnnualizedPopulationGrowthRateBetweenYears(year, year + 10)) - 100) + ")");
+        }
+        
+        List<CityDB> slowestGrowingCities = (List<CityDB>)cities.stream().sorted(new Comparator() {
+            @Override
+            public int compare(Object o1, Object o2) {
+                CityDB city1 = (CityDB) o1;
+                CityDB city2 = (CityDB) o2;
+                return city2.getAnnualizedPopulationGrowthRateBetweenYears(year, year + 10) - city1.getAnnualizedPopulationGrowthRateBetweenYears(year, year + 10) > 0.0 ? -1 : 1;
+            }
+        }).limit(5).collect(Collectors.toList());
+        
+        System.out.println("The slowest growing cities between " + year + " and " + (year + 10) + " are");
+        for (CityDB slowCity : slowestGrowingCities) {
+            System.out.println(slowCity.getName() + "(" + percentFormat.format((100 * slowCity.getAnnualizedPopulationGrowthRateBetweenYears(year, year + 10)) - 100) + ")");
+        }
+    }
+
     /**
      * Updates:
      *  - Picture