Как я могу использовать Java Stream для сокращения с этой структурой класса? - PullRequest
2 голосов
/ 11 апреля 2020

Это пример класса, над которым я работаю

public class TestReduce
{
    private static Set<Integer> seed = ImmutableSet.of(1, 2);
    public static void main(String args[]) {
        List<Accumulator> accumulators = ImmutableList.of(new Accumulator(ImmutableSet.of(5, 6)), new Accumulator(ImmutableSet.of(7, 8)));

        accumulators.stream()
                .forEach(a -> {
                    seed = a.combineResult(seed);
                });

        System.out.println(seed);
    }
}

class Accumulator
{
    public Accumulator(Set<Integer> integers)
    {
        accumulatedNumbers = integers;
    }

    public Set<Integer> combineResult(Set<Integer> numbers) {
        // Do some manipulation for the numbers 
        return (the new numbers);
    }

    private Set<Integer> accumulatedNumbers;
}

Я хотел бы уменьшить все Accumulators до набора чисел, но с начальным значением. Однако я не могу изменить сигнатуру метода combineResult. В примере я сделал это, просто используя forEach, но я не уверен, есть ли более чистый или java потоковый способ для достижения этой цели? Я пытался использовать reduce, но я не мог правильно понять аргументы reduce.

1 Ответ

4 голосов
/ 11 апреля 2020

(Ответ на оригинальный вопрос )

Это не похоже на хороший подход. Вы просто объединяете некоторые наборы.

Если вы не можете изменить подпись combineResult, вы можете сделать:

ImmutableSet<Integer> seed =
    Stream.concat(
        initialSet.stream(),
        accumulators.stream()
            // Essentially just extracting the set from each accumulator.
            // Adding a getter for the set to the Accumulator class would be clearer.
            .map(a -> a.combineResult(Collections.emptySet()))
            .flatMap(Set::stream))
        .collect(ImmutableSet.toImmutableSet());

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

В этом случае просто использовать простой старый l oop.

Set<Integer> seed = ImmutableSet.of(1, 2);
for (Accumulator a : accumulators) {
  seed = a.combineResult(seed);
}

Это позволяет избежать основной проблемы, связанной с вашим текущим подходом, а именно локальностью без потоков состояния вычисления (то есть другие потоки и предыдущие вызовы l oop не могут повлиять на текущий вызов).

...