Сумма определенных значений HashMap в списке, только если есть совпадение значения по другому ключу

У меня есть ArrayList, заполненный тысячами HashMaps с четырьмя ключами и сопоставленными с ними значениями, построенными следующим образом:

HashMap<String, Object> map = new HashMap<>();
map.put("ID", 1);
map.put("NAME", name);
map.put("WORK_TIME", workTime);
map.put("ACCOUNT", name);

теперь, имея ArrayList этих HashMaps, я хотел бы суммировать время работы людей с одинаковым идентификатором, именем и учетной записью, например:

HashMap<String, Object> map1 = new HashMap<>();
map1.put("ID", 1);
map1.put("NAME", "Edward");
map1.put("WORK_TIME", 20);
map1.put("ACCOUNT", null);

HashMap<String, Object> map2 = new HashMap<>();
map2.put("ID", 1);
map2.put("NAME", "Krzych");
map2.put("WORK_TIME", 6);
map2.put("ACCOUNT", 123);

HashMap<String, Object> map3 = new HashMap<>();
map3.put("ID", 1);
map3.put("NAME", "Edward");
map3.put("WORK_TIME", 13.5);
map3.put("ACCOUNT", null);

HashMap<String, Object> map4 = new HashMap<>();
map4.put("ID", 2);
map4.put("NAME", "Grzesiek");
map4.put("WORK_TIME", 50);
map4.put("ACCOUNT", null);

HashMap<String, Object> map5 = new HashMap<>();
map5.put("ID", 2);
map5.put("NAME", "Edward");
map5.put("WORK_TIME", 12);
map5.put("ACCOUNT", 123);

[..]

ArrayList<HashMap<String,Object>> arrList = new ArrayList<>();
arrList.put..

в результате я должен получить ArrayList из 4 HashMaps, где только два Edward HashMap с одинаковым идентификатором и учетной записью были объединены в один со временем работы 33,5.

Единственное, что я придумал, это перебирать все карты, сравнивать эти три значения, а затем успешно заменять значения рабочего времени в хэш-картах, хранящихся во втором массиве. Я работаю на Java 8 и хотел бы сделать это с помощью потоков, возможно ли это? Или вы видите лучшее решение?

Используйте конкретные классы для выполнения таких операций. например class Employee { int id; String name;int workTime;Integer account;} . Кроме того, вы можете собрать эти toMap с name в качестве ключа и соответствующим образом объединить значения.

Naman 10.04.2019 11:16

Я согласен со всеми приведенными ответами, однако, откуда берутся данные? Я предполагаю, что данные поступают из какой-то базы данных, и поэтому было бы разумно выполнить GROUP BY непосредственно на уровне базы данных.

luca.vercelli 10.04.2019 12:37

Да, вы правы, все данные берутся из базы данных. Спасибо за предложение, я попробую.

user6512569 11.04.2019 12:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
200
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

эта лямбда:

Map<String, List<HashMap<String, Object>>> xxx = arrList.stream().collect(Collectors.groupingBy(x -> ((int) x.get("ID") + "") + x.get("NAME")));

дает результат, как показано ниже:

но, как упоминалось выше, вы должны использовать (если возможно) объекты вместо массивов. С объектами лямбда будет выглядеть так:

Map<String, List<Person>> xxx = arrList.stream().collect(Collectors.groupingBy(x -> x.getName() + x. getId()));

но поскольку у вас есть класс Person, вы можете перезаписать equals в соответствии с вашими потребностями, а также сопоставить и суммировать рабочее время в одной простой лямбде:

Map<Person, Double> result = arrList.stream().collect(Collectors.groupingBy(x -> x, Collectors.summingDouble(Person::getWorkTime)));

и это результат - карта Person в качестве ключа и сводка рабочего времени в качестве значения.

код для класса Person:

public class Person {
        String name;
        int id;
        double workTime;

        public Person(String name, int id, double workTime) {
            this.name = name;
            this.id = id;
            this.workTime = workTime;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return id == person.id &&
                    Objects.equals(name, person.name);
        }

        @Override
        public int hashCode() {

            return Objects.hash(name, id);
        }
    }

пример кода:

Person person1 = new Person("Edward", 1, 20);
Person person2 = new Person("Krzych", 1, 6);
Person person3 = new Person("Edward", 1, 13.5);
Person person4 = new Person("Grzesiek", 2, 50);
Person person5 = new Person("Edward", 2, 12);

ArrayList<Person> arrList = new ArrayList<>();

arrList.add(person1);
arrList.add(person2);
arrList.add(person3);
arrList.add(person4);
arrList.add(person5);

Map<Person, Double> result = arrList.stream().collect(Collectors.groupingBy(x -> x, Collectors.summingDouble(Person::getWorkTime)));

Другие вопросы по теме