#java #hashmap #java-stream
#java #hashmap #java-поток
Вопрос:
У меня есть ArrayList, заполненный тысячами хэш-карт с четырьмя ключами и значениями, сопоставленными с ними, построенными следующим образом:
HashMap<String, Object> map = new HashMap<>();
map.put("ID", 1);
map.put("NAME", name);
map.put("WORK_TIME", workTime);
map.put("ACCOUNT", name);
теперь, имея ArrayList этих хэш-карт, я хотел бы, например, суммировать время работы людей с одинаковым идентификатором, именем и учетной записью:
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 хеш-карт, где только две хэш-карты Edward с одинаковым идентификатором и учетной записью были объединены в одну с рабочим временем 33,5.
Единственное, что я придумал, это перебирать все карты, сравнивать эти три значения, а затем успешно заменять значения рабочего времени в хэш-картах, хранящихся во втором списке массивов. Я работаю на Java 8, и я хотел бы выполнить это с помощью потоков, возможно ли это? Или вы видите лучшее решение?
Комментарии:
1. Используйте конкретные классы для выполнения таких операций. например
class Employee { int id; String name;int workTime;Integer account;}
. Кроме того, вы можете собирать ихtoMap
сname
помощью ключа as и соответствующим образом объединять значения.2. Однако я согласен со всеми приведенными ответами, откуда берутся данные? Я предполагаю, что данные поступают из какой-то базы данных, и поэтому было бы разумно выполнить GROUP BY непосредственно на уровне базы данных.
3. Да, вы правы, все данные поступают из базы данных. Спасибо за предложение, я попробую.
Ответ №1:
это лямбда:
Map<String, List<HashMap<String, Object>>> xxx = arrList.stream().collect(Collectors.groupingBy(x -> ((int) x.get("ID") "") x.get("NAME")));
дает результат, как показано ниже:
но, как упоминалось выше, вы должны использовать (если возможно) объекты вместо массивов. С объектами lambda будет выглядеть так:
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 amp;amp;
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)));