Java Карта: группировка по атрибуту ключа и максимальному превышению значения - PullRequest
3 голосов
/ 26 мая 2020

У меня есть экземпляр Map<Reference, Double> проблема в том, что ключевые объекты могут содержать ссылку на один и тот же объект, мне нужно вернуть карту того же типа "input" , но сгруппированных ключом атрибута и сохранением максимального значения.

Я пробовал использовать groupingBy и maxBy, но я застрял.

private void run () {
    Map<Reference, Double> vote = new HashMap<>();

    Student s1 = new Student(12L);
    vote.put(new Reference(s1), 66.5);
    vote.put(new Reference(s1), 71.71);
    Student s2 = new Student(44L);
    vote.put(new Reference(s2), 59.75);
    vote.put(new Reference(s2), 64.00);

    // I need to have a Collection of Reference objs related to the max value of the "vote" map
    Collection<Reference> maxVote = vote.entrySet().stream().collect(groupingBy(Map.Entry.<Reference, Double>comparingByKey(new Comparator<Reference>() {
        @Override
        public int compare(Reference r1, Reference r2) {
            return r1.getObjId().compareTo(r2.getObjId());
        }
    }), maxBy(Comparator.comparingDouble(Map.Entry::getValue))));
}

class Reference {
    private final Student student;

    public Reference(Student s) {
        this.student = s;
    }
    public Long getObjId() {
        return this.student.getId();
    }
}

class Student {
    private final  Long id;
    public Student (Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }
}

У меня ошибка в maxBy аргумент: Comparator.comparingDouble(Map.Entry::getValue) и я не знаю, как это исправить. Есть ли способ добиться ожидаемого результата?

Ответы [ 2 ]

1 голос
/ 26 мая 2020

Вы можете использовать Collectors.toMap, чтобы получить коллекцию Map.Entry<Reference, Double>

Collection<Map.Entry<Reference, Double>> result = vote.entrySet().stream()
        .collect(Collectors.toMap( a -> a.getKey().getObjId(), Function.identity(),
            BinaryOperator.maxBy(Comparator.comparingDouble(Map.Entry::getValue)))).values();

, а затем снова выполнить потоковую передачу, чтобы получить List<Reference>

List<Reference> result = vote.entrySet().stream()
        .collect(Collectors.toMap(a -> a.getKey().getObjId(), Function.identity(),
            BinaryOperator.maxBy(Comparator.comparingDouble(Map.Entry::getValue))))
        .values().stream().map(e -> e.getKey()).collect(Collectors.toList());
0 голосов
/ 26 мая 2020

Используя ваш подход groupingBy и maxBy:

Comparator<Entry<Reference, Double>> c = Comparator.comparing(e -> e.getValue());

        Map<Object, Optional<Entry<Reference, Double>>> map = 
                           vote.entrySet().stream()
                           .collect(
                            Collectors.groupingBy
                            (
                            e -> ((Reference) e.getKey()).getObjId(),                             
                            Collectors.maxBy(c)));

           // iterate to get the result (or invoke another stream)
        for (Entry<Object, Optional<Entry<Reference, Double>>> obj : map.entrySet()) {
            System.out.println("Student Id:" + obj.getKey() + ", " + "Max Vote:" + obj.getValue().get().getValue());
        }

Вывод (для ввода в ваш вопрос):

Student Id:12, Max Vote:71.71
Student Id:44, Max Vote:64.0
...