Para a questão específica de gerar um reverso IntStream
, tente algo como isto:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
Isso evita boxe e classificação.
Para a questão geral de como reverter um fluxo de qualquer tipo, não sei se existe uma maneira "adequada". Existem algumas maneiras em que posso pensar. Ambos acabam armazenando os elementos do fluxo. Não sei como reverter um fluxo sem armazenar os elementos.
Essa primeira maneira armazena os elementos em uma matriz e os lê em um fluxo na ordem inversa. Observe que, como não sabemos o tipo de tempo de execução dos elementos do fluxo, não podemos digitar a matriz corretamente, exigindo uma conversão não verificada.
@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
Object[] temp = input.toArray();
return (Stream<T>) IntStream.range(0, temp.length)
.mapToObj(i -> temp[temp.length - i - 1]);
}
Outra técnica usa coletores para acumular os itens em uma lista invertida. Isso faz muitas inserções na frente dos ArrayList
objetos, então há muitas cópias acontecendo.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
Provavelmente, é possível escrever um coletor de reversão muito mais eficiente usando algum tipo de estrutura de dados personalizada.
UPDATE 2016-01-29
Como essa pergunta recebeu um pouco de atenção recentemente, acho que devo atualizar minha resposta para resolver o problema com a inserção na frente ArrayList
. Isso será terrivelmente ineficiente com um grande número de elementos, exigindo cópia de O (N ^ 2).
É preferível usar um ArrayDeque
, que suporta com eficiência a inserção na frente. Uma pequena ruga é que não podemos usar a forma de três argumentos de Stream.collect()
; requer que o conteúdo do segundo argumento seja mesclado com o primeiro argumento e não há operação em massa "adicionar tudo à frente" Deque
. Em vez disso, usamos addAll()
para anexar o conteúdo do primeiro argumento ao final do segundo e depois retornamos o segundo. Isso requer o uso do Collector.of()
método de fábrica.
O código completo é este:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
O resultado é um em Deque
vez de um List
, mas isso não deve ser um grande problema, pois pode ser facilmente iterado ou transmitido na ordem agora invertida.
IntStream
não tem.sorted(Comparator)
método; você tem que passar por umStream<Integer>
primeiro e reverter lá antes de produzir umIntStream