#java #java-8 #java-stream
#java #java-8 #java-поток
Вопрос:
Предположим, у меня есть следующая структура класса:
@Getter
@Setter
public class Section {
private Long id;
private Set<Grid> grids;
}
@Getter
@Setter
public class Grid {
private Long id;
private Set<Row> rows;
}
@Getter
@Setter
public class Row {
private Long id;
private String email;
}
и у меня есть этот набор объектов:
Set<Section> sections;
давайте представим, что этот раздел устанавливает значения в виде JSON в следующей структуре :
[
{
"id": 1,
"grids": [
{
"id": 10,
"rows" [
{
"id": 50,
"email": "email1@test.com"
},
{
"id": 51,
"email": "email2@test.com"
}
]
}
]
},
{
"id": 2,
"grids": [
{
"id": 11,
"rows" [
{
"id": 60,
"email": "email1@test.com"
}
]
}
]
}
]
Просто представьте, что у меня есть несколько разделов, и эти разделы имеют несколько сеток, и каждая сетка имеет несколько строк, и атрибут email в каждой строке может существовать в разных сетках.
Теперь мне нужно преобразовать этот набор в java.util.Map<String, Set>, и эта карта представляет адрес электронной почты объекта строки в качестве ключа и группу идентификаторов разделов в качестве значения этого ключа карты. поэтому мне нужен результат, подобный этому Map<email, Set<section1Id, section2id и т. Д.>> что-то вроде этого в JSON (это просто для уточнения идеи):
[
{
"key": "email1@test.com",
"value": [1, 2] // Section ids
},
{
"key": "email2@test.com",
"value": [1] // Section ids
}
]
OR like that (whatever)
[
"email1@test.com": {1, 2},
"email2@test.com": {1}
]
Как я могу добиться этого, используя потоковую передачу Java 8?
Ответ №1:
Попробуйте что-то вроде этого:
import static java.util.stream.Collectors.*;
import org.apache.commons.lang3.tuple.Pair;
// ...snip...
sections.stream()
.flatMap(section->section.getGrids()
.stream()
.map(Grid::getRows)
.flatMap(Set::stream)
.map(row->new Pair(row.getEmail(), section.getId())))
.collect(groupingBy(Pair::getKey, mapping(Pair::getValue, toSet())));
Ответ №2:
Если вы используете Java 9 или новее, вы можете сделать это очень лаконично, не прибегая к сторонним библиотекам:
import java.util.Map;
import java.util.Set;
import static java.util.Map.Entry;
import static java.util.Map.entry;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toSet;
Map<String, Set<Long>> result = sections.stream()
.flatMap(section -> section.getGrids().stream()
.flatMap(grid -> grid.getRows().stream())
.map(row -> entry(row.getEmail(), section.getId())))
.collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toSet())));
Комментарии:
1. Проблема в том, что для этого проекта я использую java8, я знаю, что это применимо для выполнения этого простым способом из java9, но, как вы видите, я написал java8 в заголовке вопроса. в любом случае, спасибо за ваш комментарий.
2. Чтобы обойти отсутствие метода Java 9 Map.entry(), вы можете использовать кортеж Apache Commons или создать свой собственный вспомогательный класс.
Ответ №3:
Речь идет не о потоковой передаче. Это может быть достигнуто с помощью простого foreach:
public static void main(String[] args) {
Set<Section> sections = Set.of(....);
Map<String, Set<Long>> result = new HashMap<>();
sections.forEach(section ->
section.getGrids()
.forEach(grid ->
grid.getRows().forEach(row -> {
if (result.containsKey(row.getEmail()))
result.get(row.getEmail()).add(section.getId());
else result.put(row.getEmail(), Set.of(section.getId()));
})));
}
Комментарии:
1. Я уже делаю это с помощью этого простого для каждого 🙂 но мне это нужно с помощью потоковой передачи, в любом случае спасибо за ваш комментарий.
Ответ №4:
Вот двухэтапная операция для получения желаемого выходного формата. Посмотрите на это, если подходит для вашего варианта использования
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javafx.util.Pair;
public class P5 {
public static void main(String[] args) {
Row r1 = new Row(50L, "email1@test.com");
Row r2 = new Row(51L, "email2@test.com");
Row r3 = new Row(60L, "email1@test.com");
Row[] arr1 = {r1, r2};
Row[] arr2 = {r3};
Grid[] g1 = {new Grid(10L, new HashSet<>(Arrays.asList(arr1)))};
Grid[] g2 = {new Grid(11L, new HashSet<>(Arrays.asList(arr2)))};
Set<Section> sections = new HashSet<>();
sections.add(new Section(1L, new HashSet<>(Arrays.asList(g1))));
sections.add(new Section(2L, new HashSet<>(Arrays.asList(g2))));
Map<Long, List<String>> minify = sections.stream()
.collect(Collectors.toMap(section -> section.id,
section -> section.grids.stream().flatMap(grid -> grid.rows.stream())
.map(row -> row.email)
.collect(Collectors.toList())));
Map<String, Set<Long>> result = minify.keySet().stream()
.flatMap(key -> minify.get(key).stream().map(email -> new Pair<>(
key, email))).collect(Collectors.groupingBy(
Pair::getValue, Collectors.mapping(Pair::getKey, Collectors.toSet())));
System.out.println(result);
}
static class Section {
private Long id;
private Set<Grid> grids;
public Section(Long id, Set<Grid> grids) {
this.id = id;
this.grids = grids;
}
}
static class Grid {
private Long id;
private Set<Row> rows;
public Grid(Long id, Set<Row> rows) {
this.id = id;
this.rows = rows;
}
}
static class Row {
private Long id;
private String email;
public Row(Long id, String email) {
this.id = id;
this.email = email;
}
}
}
Результат
{email2@test.com=[1], email1@test.com=[1, 2]}