Как получить все элементы во вложенной коллекции с потоками - PullRequest
2 голосов
/ 01 июня 2019

У меня есть класс, который содержит разные вложенные коллекции, теперь я хочу получить все элементы вложенных коллекций, в частности, я хочу собрать все StrokePoints коллекций. Я могу решить это со "старой" Java, но как это сделать с потоками?

    int strokesCounter = 0;
    List<StrokePoint> pointList = new ArrayList<>();
    if (!strokesData.getListOfSessions().isEmpty()) {
        for (SessionStrokes session : strokesData.getListOfSessions()) {
            List<Strokes> strokes = session.getListOfStrokes();
            for (Strokes stroke : strokes) {
                strokesCounter++;
                List<StrokePoint> points = stroke.getListOfStrokePoints();
                pointList.addAll(stroke.getListOfStrokePoints());        
            }
        }
    }

Я ищу способ заполнить pointList функцией потоков.

Ответы [ 4 ]

2 голосов
/ 01 июня 2019

Вы можете просто использовать Stream.flatMap() дважды:

List<StrokePoint> pointList = strokesData.getListOfSessions().stream()
        .flatMap(session -> session.getListOfStrokes().stream())
        .flatMap(strokes -> strokes.getListOfStrokePoints().stream())
        .collect(Collectors.toList());

Если вам нужно сосчитать список штрихов, вы можете разделить его на две части и использовать List.size():

List<Strokes> strokesList = strokesData.getListOfSessions().stream()
        .flatMap(session -> session.getListOfStrokes().stream())
        .collect(Collectors.toList());
int strokesCounter = strokesList.size();
List<StrokePoint> pointList = strokesList.stream()
        .flatMap(strokes -> strokes.getListOfStrokePoints().stream())
        .collect(Collectors.toList());

В качестве альтернативы вы можете увеличить AtomicInteger на flatMap():

final AtomicInteger strokesCounter = new AtomicInteger();
List<StrokePoint> pointList = strokesData.getListOfSessions().stream()
        .flatMap(session -> {
            List<Strokes> strokes = session.getListOfStrokes();
            strokesCounter.addAndGet(strokes.size());
            return strokes.stream();
        })
        .flatMap(strokes -> strokes.getListOfStrokePoints().stream())
        .collect(Collectors.toList());

Или с peek():

final AtomicInteger strokesCounter = new AtomicInteger();
List<StrokePoint> pointList = strokesData.getListOfSessions().stream()
        .flatMap(session -> session.getListOfStrokes().stream())
        .peek(i -> strokesCounter.incrementAndGet())
        .flatMap(strokes -> strokes.getListOfStrokePoints().stream())
        .collect(Collectors.toList());
2 голосов
/ 01 июня 2019

Сглаживать вложенные данные довольно просто:

List<StrokePoint> pointList = strokesData.getListOfSessions()
        .streams()
        .map(SessionStrokes::getListOfStrokes)
        .flatMap(List::stream)
        .map(Strokes::getListOfStrokePoints)
        .flatMap(List::stream)
        .collect(Collectors.toList());

Сбор количества ходов по пути более сложен и несколько спорен. Вы можете создать

AtomicInteger strokesCounter = new AtomicInteger();

и увеличивать его сразу после первого flatMap:

.peek(strokesCounter::incrementAndGet)
1 голос
/ 01 июня 2019

Поскольку основной целью является решение для сбора List<StrokePoint>, вы можете выполнить его с помощью операции flatMap следующим образом:

List<StrokePoint> points = strokesData.getListOfSessions()
        .stream()
        .flatMap(ss -> ss.getListOfStrokes().stream()
                .flatMap(s -> s.getListOfStrokePoints().stream()))
        .collect(Collectors.toList());

Кроме того, счет Stroke с также может бытьвычисляется с использованием потоков путем суммирования размера списков следующим образом:

long strokeCount = strokesData.getListOfSessions()
        .stream()
        .mapToLong(ss -> ss.getListOfStrokes().size())
        .sum();

Чтобы объединить эти операции, вы можете создать AbstractMap.SimpleEntry, уменьшив записи следующим образом:

AbstractMap.SimpleEntry<Integer, Stream<StrokePoint>> reduce = strokesData.getListOfSessions()
        .stream()
        .map(ss -> new AbstractMap.SimpleEntry<>(ss.getListOfStrokes().size(),
                ss.getListOfStrokes()
                        .stream()
                        .flatMap(s -> s.getListOfStrokePoints().stream())))
        .reduce(new AbstractMap.SimpleEntry<>(1, Stream.empty()),
                (e1, e2) -> new AbstractMap.SimpleEntry<>(
                        Integer.sum(e1.getKey(), e2.getKey()),
                        Stream.concat(e1.getValue(), e2.getValue())));

Используя эту запись, вы можете получить число Stroke с и список StrokePoint с:

long strokeCount = reduce.getKey();
List<StrokePoint> strokePoints = reduce.getValue().collect(Collectors.toList());
0 голосов
/ 01 июня 2019

Если вы беспокоитесь о побочных эффектах, это сработает (но оба других ответа на момент написания являются бесконечно более читабельными):

    Entry<Integer, List<StrokePoint>> summary = //
            strokesData.getListOfSessions()
                       .stream()
                       .flatMap(session -> session.getListOfStrokes().stream())
                       .map(strokes -> new SimpleEntry<>(1, strokes.getListOfStrokePoints()))
                       .reduce((l1, l2) -> {
                           int count = l1.getKey() + l2.getKey();

                           List<StrokePoint> list = l1.getValue();
                           list.addAll(l2.getValue());

                           return new SimpleEntry<>(count, list);
                       })
                       .orElse(new SimpleEntry<>(0, Collections.emptyList()));

    strokesCounter = summary.getKey();
    pointList = summary.getValue();

РЕДАКТИРОВАНИЕ для добавления проверки:

public class Scratch {
    public static void main(String[] args) {
        int strokesCounter = 0;
        List<StrokePoint> pointList = new ArrayList<>();
        StrokesData strokesData = new StrokesData();

        SessionStrokes sessionStrokes = new SessionStrokes();
        strokesData.sessionStrokes.add(sessionStrokes);

        Strokes s1 = new Strokes();
        sessionStrokes.strokesList.add(s1);

        s1.strokePoints.add(new StrokePoint());
        s1.strokePoints.add(new StrokePoint());

        Strokes s2 = new Strokes();
        sessionStrokes.strokesList.add(s2);

        s2.strokePoints.add(new StrokePoint());
        s2.strokePoints.add(new StrokePoint());
        s2.strokePoints.add(new StrokePoint());
        s2.strokePoints.add(new StrokePoint());
        s2.strokePoints.add(new StrokePoint());
        s2.strokePoints.add(new StrokePoint());

        Entry<Integer, List<StrokePoint>> summary = //
                strokesData.getListOfSessions()
                           .stream()
                           .flatMap(session -> session.getListOfStrokes()
                                                      .stream())
                           .map(strokes -> new SimpleEntry<>(1, strokes.getListOfStrokePoints()))
                           .reduce((l1, l2) -> {
                               int count = l1.getKey() + l2.getKey();

                               List<StrokePoint> list = l1.getValue();
                               list.addAll(l2.getValue());

                               return new SimpleEntry<>(count, list);
                           })
                           .orElse(new SimpleEntry<>(0, Collections.emptyList()));

        strokesCounter = summary.getKey();
        pointList = summary.getValue();

        System.out.println(strokesCounter);
        System.out.println(pointList);
    }
}

class StrokesData {

    List<SessionStrokes> sessionStrokes = new ArrayList<>();

    public List<SessionStrokes> getListOfSessions() {
        return sessionStrokes;
    }
}

class SessionStrokes {

    List<Strokes> strokesList = new ArrayList<>();

    public List<Strokes> getListOfStrokes() {
        return strokesList;
    }

}

class Strokes {

    List<StrokePoint> strokePoints = new ArrayList<>();

    public List<StrokePoint> getListOfStrokePoints() {
        return strokePoints;
    }
}

class StrokePoint {
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...