Установить в Map<String, установить> java8

#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]}