Потоки Java 8 - изменение всех элементов в группе - PullRequest
0 голосов
/ 01 декабря 2018

У меня есть коллекция объектов класса A

class A {
    String code;
    long timestamp;
    long largestTimestamp;
}

Мне нужно заполнить поле mostTimestamp для каждого объекта (наибольшее значение «timestamp» в группе объектов с одинаковым кодом).Я могу сделать это в два этапа следующим образом -

Map<String, Long> largestTimestampMap = list.stream().collect(Collectors.toMap(A::getCode, A::getTimestamp, Long::max));
list.forEach(a -> a.setLargestTimestamp(largestTimestampMap.get(a.getCode())));

Есть ли способ объединить их в одну цепочку потока?

Ответы [ 3 ]

0 голосов
/ 01 декабря 2018

Да, вы можете объединить их в один конвейер следующим образом:

list.stream()
     .map(a -> new A(a.getCode(), a.getTimestamp(),
                list.stream()
                    .filter(b -> a.getCode().equals(b.getCode()))
                    .mapToLong(A::getTimestamp)
                    .max().getAsLong()))           
     .collect(Collectors.toList());

или если вы хотите избежать создания нового списка, но вместо этого изменить существующий, как в вашемзатем используйте replaceAll:

list.replaceAll(a -> new A(a.getCode(), a.getTimestamp(),
                        list.stream()
                                .filter(b -> a.getCode().equals(b.getCode()))
                                .mapToLong(A::getTimestamp)
                                .max().getAsLong()));

Однако я бы рекомендовал избегать этого подхода:

1), поскольку он имеет более низкую производительность, чем ваша текущая реализация, это решение требует итерации по list снова forEach элемент в нем.Принимая во внимание, что подход к карте, который вы показали, требует только одного вызова get, и мы все знаем, насколько быстро выполняется поиск на карте.

2) Там больше кода.

Да, вы можете преобразовать код внутри промежуточной операции map в метод, чтобы он выглядел короче, но в конечном итоге он все еще длиннее.

Иногда лучший подход требует двух или более отдельных строк, и в этом случае лучше продолжить ваш подход.

0 голосов
/ 03 декабря 2018

Просто другая мысль, но вы не можете структурировать свой класс A, как показано ниже

class A {
  String code;
  long timeStamp;
  TimeStampWrapper timeStampWrapper;
}

class TimeStampWrapper {
  long maxTimeStamp;
  long minTimeStamp;
  ...
}

При таком подходе вам потребуется только 1 обход потока и всего одна операция набора для установки maxTimeStamp,minTimeStamp и т. д. и т. д.

0 голосов
/ 01 декабря 2018

Возможно, вы просто искали (если заполнить поле самое большое время для каждого объекта означает сохранение одного и того же largestTimeStamp для всего списка):

// find the largest timestamp
long largestTimeStamp = list.stream()
        .mapToLong(A::getTimestamp)
        .max()
        .orElse(Long.MIN_VALUE);

// iterate through the list to set its value
list.forEach(a -> a.setLargestTimestamp(largestTimeStamp));

ЕслиОбязательно делать это в одной строке кода, которую вы можете использовать (отредактировано для соответствия существующему коду, как пояснил Аомин в комментариях):

List<A> output = list.stream()
        .map(a -> new A(a.getCode(), a.getTimestamp(),
                list.stream().filter(b -> a.getCode().equals(b.getCode()))
                        .mapToLong(A::getTimestamp).max().orElse(a.getTimestamp())))
        .collect(Collectors.toList());
...