Examples covering inheritance, collections, and exceptions.
Write a program that counts the number of gold, silver, and bronze medals
won by each country in the Olympic Games. Your program should accept accept
input from the keyboard until the user types the sentinel string "done"
(alternatively, you can read from a file because the input is very long).
Assume that the input is line based, with the results for an event given as a comma-delimited list of fields:
men's curling, Canada, Finland, USA
where the first field is the event name, the second field is the gold medal winning country, the third field is the silver medal winning country, and the fourth field is the bronze medal winning country (note that this problem ignores the case where a tie has occurred). If a field is missing from the input, your program should print a warning message and ignore the line of input.
Your program should output the medal count for each country in order of the number of gold medals won. If there is tie for the number of gold medals won, the countries that tied should be listed in alphabetic order.
Sample Input: (based on the Turin 2006 Winter Olympics)
men's curling, Canada, Finland, USA women's curling, Sweden, Switzerland, Canada men's ice hockey, Sweden, Finland, Czech Republic women's ice hockey, Canada, Sweden, USA men's skeleton, Canada, Canada, Switzerland women's skeleton, Switzerland, Great Britain, Canada men's luge, Italy, Russia, Latvia women's luge, Germany, Germany, Germany mixed luge, Austria, Germany, Italy men's 4 x 7.5 km relay biathlon, Germany, Russia, France men's 12.5 km pursuit biathlon, France, Norway, Germany men's 20 km individual biathlon, Germany, Norway, Norway women's 4 x 6 km relay biathlon, Russia, Germany, France women's 10 km pursuit biathlon, Germany, Germany, Russia women's 15 km individual biathlon, Russia, Germany, Russia men's halfpipe snowboarding, USA, USA, Finland women's halfpipe snowboarding, USA, USA, Norway some made up event, Canada, Bosnia and Herzegovina, Serbia and Montenegro done
Sample Output:
Your program should output the country name using 25 spaces, and
each number of medals using 3 spaces.
Canada 4 1 2 Germany 4 5 2 Russia 2 2 2 Sweden 2 1 0 USA 2 2 2 Austria 1 0 0 France 1 0 2 Italy 1 0 1 Switzerland 1 1 1 Bosnia and Herzegovina 0 1 0 Czech Republic 0 0 1 Finland 0 2 1 Great Britain 0 1 0 Latvia 0 0 1 Norway 0 2 2 Serbia and Montenegro 0 0 1
Perhaps the most straightforward way of solving the problem is to use
3 maps; one that maps country names to gold medal counts,
one that maps country names to silver medal counts, and
one that maps country names to bronze medal counts. If you use TreeMap
for each map, you can solve half of the output problem because the country
names will be sorted alphabetically for you.
One thing to watch out for is to make sure a country that wins a medal shows up in all of the maps. For example, in the example input, Latvia won only a bronze medal, but Latvia should show up in the gold medal map (with 0 gold medals won) and the silver medal map (with 0 silver medals won) in addition to the bronze medal map (with 1 bronze medal won). If you forget to do this, outputting the results becomes even more complicated.
import java.util.*; import java.io.*; public class MedalCount1 { public static void main(String[] args) { PrintStream output = System.out; Scanner input = new Scanner(System.in); Map<String, Integer> goldMedals = new TreeMap<String, Integer>(); Map<String, Integer> silverMedals = new TreeMap<String, Integer>(); Map<String, Integer> bronzeMedals = new TreeMap<String, Integer>(); String lineIn = input.nextLine(); while (!lineIn.equals("done")) { try { StringTokenizer tok = new StringTokenizer(lineIn, ","); // tok will throw an exception on nextToken if there are // missing fields; catch the NoSuchElementException to // solve the input validation problem String event = tok.nextToken().trim(); // gold, silver, and bronze winning countries String goldCountry = tok.nextToken().trim(); String silverCountry = tok.nextToken().trim(); String bronzeCountry = tok.nextToken().trim(); // Update gold medal country by adding 1 to their // gold medal counts; also, add the country to // the silverMedals and bronzeMedals maps if necessary Integer oldGold = goldMedals.get(goldCountry); if (oldGold == null) { oldGold = 0; } goldMedals.put(goldCountry, oldGold + 1); if (silverMedals.get(goldCountry) == null) { silverMedals.put(goldCountry, 0); } if (bronzeMedals.get(goldCountry) == null) { bronzeMedals.put(goldCountry, 0); } // Update silver medal country by adding 1 to their // silver medal counts; also, add the country to // the goldMedals and bronzeMedals maps if necessary Integer oldSilver = silverMedals.get(silverCountry); if (oldSilver == null) { oldSilver = 0; } silverMedals.put(silverCountry, oldSilver + 1); if (goldMedals.get(silverCountry) == null) { goldMedals.put(silverCountry, 0); } if (bronzeMedals.get(silverCountry) == null) { bronzeMedals.put(silverCountry, 0); } // Update bronze medal country by adding 1 to their // bronze medal counts; also, add the country to // the goldMedals and silverMedals maps if necessary Integer oldBronze = bronzeMedals.get(bronzeCountry); if (oldBronze == null) { oldBronze = 0; } bronzeMedals.put(bronzeCountry, oldBronze + 1); if (goldMedals.get(bronzeCountry) == null) { goldMedals.put(bronzeCountry, 0); } if (silverMedals.get(bronzeCountry) == null) { silverMedals.put(bronzeCountry, 0); } } catch (NoSuchElementException ex) { output.println("\tMissing field on input!"); } lineIn = input.nextLine(); } // Gold medal counts: // Find the unique gold medal counts by putting the goldMedal // values into a TreeSet TreeSet<Integer> ascendingGoldCounts = new TreeSet<Integer>(goldMedals.values()); // Reverse the set so that we get the unique gold medal counts // in descending order (from largest to smallest) Set<Integer> goldCounts = ascendingGoldCounts.descendingSet(); // For each number of gold medals won (from largest to smallest) for (Integer numGold : goldCounts) { // Find the countries that won numGold for (String country : goldMedals.keySet()) { Integer thisGold = goldMedals.get(country); if (thisGold.equals(numGold)) { Integer thisSilver = silverMedals.get(country); Integer thisBronze = bronzeMedals.get(country); output.printf("%25s %2s %2s %2s%n", country, thisGold.toString(), thisSilver.toString(), thisBronze.toString()); } } } } }
Instead of using three maps, you can use one map that maps country names to a list of the number of gold, silver, and bronze medals won.
import java.util.*; import java.io.*; public class MedalCount2 { public static void main(String[] args) { PrintStream output = System.out; Scanner input = new Scanner(System.in); Map<String, List<Integer>> medals = new TreeMap<String, List<Integer>>(); String lineIn = input.nextLine(); while (!lineIn.equals("done")) { try { StringTokenizer tok = new StringTokenizer(lineIn, ","); // tok will throw an exception on nextToken if there are // missing fields; catch the NoSuchElementException to // solve the input validation problem String event = tok.nextToken().trim(); // gold, silver, and bronze winning countries String country1 = tok.nextToken().trim(); String country2 = tok.nextToken().trim(); String country3 = tok.nextToken().trim(); // update the gold medal winning country List<Integer> medals1 = medals.get(country1); if (medals1 == null) { medals1 = new ArrayList<Integer>(); medals1.add(1); medals1.add(0); medals1.add(0); } else { int numGold = medals1.get(0); medals1.set(0, numGold + 1); } medals.put(country1, medals1); // update the silver medal winning country List<Integer> medals2 = medals.get(country2); if (medals2 == null) { medals2 = new ArrayList<Integer>(); medals2.add(0); medals2.add(1); medals2.add(0); } else { int numSilver = medals2.get(1); medals2.set(1, numSilver + 1); } medals.put(country2, medals2); // update the bronze medal winning country List<Integer> medals3 = medals.get(country3); if (medals3 == null) { medals3 = new ArrayList<Integer>(); medals3.add(0); medals3.add(0); medals3.add(1); } else { int numBronze = medals3.get(2); medals3.set(2, numBronze + 1); } medals.put(country3, medals3); } catch (NoSuchElementException ex) { output.println("\tMissing field on input!"); } lineIn = input.nextLine(); } // Gold medal counts: // Find the unique gold medal counts by putting the number // of gold medals won by each country into a TreeSet TreeSet<Integer> ascendingGoldCounts = new TreeSet<Integer>(); for (List<Integer> countryMedalCount : medals.values()) { ascendingGoldCounts.add(countryMedalCount.get(0)); } // Reverse the set so that we get the unique gold medal counts // in descending order (from largest to smallest) Set<Integer> goldCounts = ascendingGoldCounts.descendingSet(); // For each number of gold medals won (from largest to smallest) for (Integer numGold : goldCounts) { // Find the countries that won numGold for (String country : medals.keySet()) { Integer thisGold = medals.get(country).get(0); if (thisGold.equals(numGold)) { Integer thisSilver = medals.get(country).get(1); Integer thisBronze = medals.get(country).get(2); output.printf("%25s %2s %2s %2s%n", country, thisGold.toString(), thisSilver.toString(), thisBronze.toString()); } } } } }
You could also use four parallel lists, one for the countries, and one each for the number of gold, silver, and bronze medals won. The important detail to watch out for is that you make sure you update the lists so that they remain synchronized with each other: the element at index 0 in the gold medal list should be the number of gold medals won by the country at element 0 in the country list (and similarly for the silver and bronze metal lists).
Outputting the results is slightly harder because the list of countries cannot be sorted without destroying its relationship to the medal lists.
import java.util.*; import java.io.*; public class MedalCount3 { public static void main(String[] args) { PrintStream output = System.out; Scanner input = new Scanner(System.in); List<String> country = new ArrayList<String>(); List<Integer> gold = new ArrayList<Integer>(); List<Integer> silver = new ArrayList<Integer>(); List<Integer> bronze = new ArrayList<Integer>(); String lineIn = input.nextLine(); while (!lineIn.equals("done")) { try { StringTokenizer tok = new StringTokenizer(lineIn, ","); String event = tok.nextToken().trim(); // tok will throw an exception on nextToken if there are // missing fields; catch the NoSuchElementException to // solve the input validation problem // gold, silver, and bronze winning countries String country1 = tok.nextToken().trim(); String country2 = tok.nextToken().trim(); String country3 = tok.nextToken().trim(); // update the gold medal winning country int index = country.indexOf(country1); if (index == -1) { country.add(country1); gold.add(1); silver.add(0); bronze.add(0); } else { int numGold = gold.get(index); gold.set(index, numGold + 1); } // update the silver medal winning country index = country.indexOf(country2); if (index == -1) { country.add(country2); gold.add(0); silver.add(1); bronze.add(0); } else { int numSilver = silver.get(index); silver.set(index, numSilver + 1); } // update the bronze medal winning country index = country.indexOf(country3); if (index == -1) { country.add(country3); gold.add(0); silver.add(0); bronze.add(1); } else { int numBronze = bronze.get(index); bronze.set(index, numBronze + 1); } } catch (NoSuchElementException ex) { output.println("\tMissing field on input!"); } lineIn = input.nextLine(); } // gold medal counts TreeSet<Integer> ascendingGoldCounts = new TreeSet<Integer>(gold); Set<Integer> goldCounts = ascendingGoldCounts.descendingSet(); // For each number of gold medals won (from largest to smallest) for (Integer numGold : goldCounts) { Set<String> result = new TreeSet<String>(); // Find the countries that won numGold for (int i = 0; i < country.size(); i++) { Integer thisGold = gold.get(i); if (thisGold.equals(numGold)) { Integer thisSilver = silver.get(i); Integer thisBronze = bronze.get(i); String thisResult = String.format("%s %2s %2s %2s", country.get(i), thisGold.toString(), thisSilver.toString(), thisBronze.toString()); result.add(thisResult); } } for (String s : result) { output.printf("%34s%n", s); } } } }