Like most AoC second-star problems, this one builds on the first star, and, actually, in this case, requires only minimal changes.
The second star, accessible only if you have completed the first, asks this time
for the total consumed by the three hungriest elves—the champion you found for
the first star, plus the second- and third-place elves.
That can be done with this very simple method, which, including comments and
white space, is not even 10 lines:
private static int getSumOfTopNElements(List<Integer> elfCalories, int maxIndex)
{
int topNElfCals = 0;
// given a sorted list, take the
running sum of the elements up to maxIndex
for (int i = 0; i < maxIndex;
i++) {
topNElfCals += elfCalories.get(i);
}
// return that sum
return topNElfCals;
}
maxIndex in this case is always 3, and a good IDE like IntelliJ (even the
Community Edition) will flag this. But I have a reason for building it like
this, and not hardcoding the three.
Building the method like this, and allowing any index to be
passed—even if we know that, for the elves’ purposes, that index will always be
3—allows the code to be much more portable, and called on by someone else in totally
different circumstances who needs to find the total of the first few elements
of a sorted list of Grades or Salaries or SquareFootages or what have you. This
way, you do not care what the list is for—it could be elves and their diets, or
anything else—nor do you care about which index you go to.
There’s another reason for writing like this over hardcoding a 3 or another number:
if you hard-code it, you’ll have to remember to find and change every
hard-coded instance, in order not to have inconsistencies, if you ever want
more or less than the top 3. But if you pass in the 3 (or any other number)
dynamically as we have done here, you make it so that the number can change
freely without ever having to make those changes—or, by greatly diminishing the
number of places where code would have to change if you wanted to modify the
logic. It is a good idea to write as generically as possible, hardcoding as
little as possible, because each time you hard-code something, you make your
code a little more restrictive, harder to maintain, and harder to understand.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ElfCalorieCounter {
public static void main(String[] args)
throws IOException {
// create a reader object to
read through the input file
BufferedReader reader = new
BufferedReader(new FileReader("C:\\Users\\andre\\IdeaProjects\\JavaPractice\\src\\main\\java\\elfCalories.txt"));
// calculate all the calorie
counts of the elves
List<Integer> elfCalories
= calculateCalories(reader);
reader.close();
// sort, then reverse the
list
prepareList(elfCalories);
// find the sum of the top 3
best-performing elves
int top3Cals = getSumOfTopNElements(elfCalories,
3);
// display the calorie
counts of all elves
System.out.println("Calories
per elf: " + elfCalories);
// display the calorie count
of the 3 most productive, summed together
System.out.println("The
calories collected by the top 3 most productive elves: " + top3Cals);
System.out.println("elfCalories.size()
= " + elfCalories.size());
}
private static int getSumOfTopNElements(List<Integer>
elfCalories, int maxIndex) {
int topNElfCals = 0;
// given a sorted list, take
the running sum of the elements up to maxIndex
for (int i = 0; i < maxIndex;
i++) {
topNElfCals += elfCalories.get(i);
}
// return that sum
return topNElfCals;
}
private static void prepareList(List<Integer>
elfCalories) {
Collections.sort(elfCalories);
Collections.reverse(elfCalories);
}
/**
* @param reader BufferedReader
object reads file line by line
* @return a list containing the
calorie counts of various elves
*/
private static List<Integer>
calculateCalories(BufferedReader reader) throws IOException {
String line;
List<Integer> elfCalories
= new ArrayList<>();
int totalCalories = 0;
// while there are still
lines of calories
while ((line = reader.readLine())
!= null) {
int calories;
// when you hit a blank
line, a given elf is done collecting calories
// add its total to the
list and zero out the total to get ready for the next elf
if (line.isEmpty()) {
elfCalories.add(totalCalories);
totalCalories = 0;
}
// but if the same elf
is still collecting calories, then the elf's running total of calories
// is how many calories
they've collected up until now, plus the calories they just collected on this
line
else {
calories = Integer.parseInt(line);
totalCalories += calories;
}
}
// return a list of calorie
counts where 1 number = the production of 1 elf
return elfCalories;
}
}
No comments:
Post a Comment