My current code:
List<Float> totalAmounts = sources.stream().collect(Collectors.groupingBy(Cause::getAmount, Collectors.counting())) .entrySet().stream().sorted(entryComp).map(Map.Entry::getValue).limit(3).toList(); The idea, is that it adds up all of Cause.getAmount(), which is a float into a list of max 3 elements The Cause class constructor looks like this, Cause has all getters and setters.
public Cause(String name, int time, float amount) {} For example, the sources list would look like
new Cause("Name", 34, 15.53F); new Cause("Name", 636, 2.12F); new Cause("Name", 2345, 3.14F); new Cause("Name", 568, 9F); new Cause("OtherName", 10, 5.55F); new Cause("OtherName", 5324, 0.27F); new Cause("OtherName", 1, 6.21F); new Cause("RealName", 921, 7.05F); new Cause("RealName", 3899, 11.11F); new Cause("RealName", 1782, 8.38F); new Cause("BadName", 234, 1.01F); new Cause("BadName", 581, 6.31F); and the expected result of totalAmounts as the full <K, V> would be
(4, 29.79F) (3, 12.03F) (3, 26.54F) (I am aware I am only pulling the Entry::getValue ) The key is the number of equal strings The value is the sum of all objects with the equal strings' last constructor parameter (It must be either a double or float) Here's my whole code.
List<Cause> sources = new CopyOnWriteArrayList<>(); private String topThree() { StringBuilder result = new StringBuilder(); Comparator<Map.Entry<String, Long>> entryComparator = Collections.reverseOrder(Map.Entry.comparingByValue()); Comparator<Map.Entry<Float, Double>> entryComp = Collections.reverseOrder(Map.Entry.comparingByValue()); List<String> most = sources.stream().collect(Collectors.groupingBy(Cause::getName, Collectors.counting())) .entrySet().stream().sorted(entryComparator).map(Map.Entry::getKey).limit(3).toList(); List<Long> mostTimes = sources.stream().collect(Collectors.groupingBy(Cause::getName, Collectors.counting())) .entrySet().stream().sorted(entryComparator).map(Map.Entry::getValue).limit(3).toList(); List<Float> total = sources.stream().collect(Collectors.groupingBy(Cause::getAmount, Collectors.counting())) .entrySet().stream().sorted(entryComp).map(Map.Entry::getValue).limit(3).toList(); for (int i = 0; i < most.size(); i++) { try { result.append((i+1) + ". " + most.get(i) + " " + mostTimes.get(i) + " " + total.get(i) + "\n"); } catch (ArrayIndexOutOfBoundsException ignored) {} } return result.toString(); } @Getter @Setter private static final class Cause { private Source source; private String name; private float amount; private int tickRecordedOn; public Cause(Source source, String name, float amount, int tickRecordedOn) { this.source = source; this.name = name; this.amount = amount; this.tickRecordedOn = tickRecordedOn;// Used for syncing, nothing else } } The idea behind the topThree method is to return
(Cause Name) (Amount of times the Cause name is in the list) (The sum of the Cause amount) Basically condensing the list of Cause into a single string that is Cause, just added up each value.