How to xor predicates? - java

I need a method where I need to xor Predicates which I will recieve as method params. I have a somewhat working but cumbersome solution for two predicates. To give a simple, minimal and reproducible example:
Predicate<String> pred1 = s -> s.contains("foo");
Predicate<String> pred2 = s -> s.contains("bar");
String toTest = "foobar";
The logical OR will return true for given predicates and the test string:
boolean oneOnly = pred1.or(pred2).test(toTest);
but for my use case it should return false since both substrings are included. It should only return true if and only if one condition is met.
For two prdeicates I have this
static boolean xor(Predicate<String> pred1, Predicate<String> pred2, String toTest){
return pred1.and(pred2.negate()).or(pred2.and(pred1.negate())).test(toTest);
}
Is there a simple but a convinient way to xor predicates?

In followup to #xdhmoore's answer, that's overkill and can be done much simpler:
static <T> Predicate<T> xor(Predicate<T> pred1, Predicate<T> pred2) {
return t -> pred1.test(t) ^ pred2.test(t);
}

Update:
Below are some examples of why you'd want to return a Predicate instead of a boolean, but #rzwitserloot's answer does it nicely and more succinctly.
To play the Devil's advocate: it's less pretty, but one advantage for the way you already have it is you are slightly more in line with the Predicate idioms. A little tweaking gets you:
Return a Predicate
static <T> Predicate<T> xor(Predicate<T> pred1, Predicate<T> pred2){
return pred1.and(pred2.negate())
.or(pred2.and(pred1.negate()));
}
// Which means you can do this, which is probably more conducive to combining your
// new xor function with other predicates:
xor((Integer a) -> a > 1, (Integer b) -> b < 10).test(0));
// For example, because you return a Predicate:
xor((Integer a) -> a > 1, (Integer b) -> b < 10).negate().test(0));
Return a boolean
static <T> boolean xor(Predicate<T> pred1, Predicate<T> pred2, T toTest) {
return pred1.test(toTest) ^ pred2.test(toTest);
}
// In contrast, if your xor function returns a boolean, you get this, which is
// similar, but is less conducive to using all the Predicate methods:
xor((Integer a) -> a > 1, (Integer b) -> b < 10, 14);
// To be honest, this seems more readable to me than the negate() function in the
// example above, but perhaps there are scenarios where the above is preferred...
!xor((Integer a) -> a > 1, (Integer b) -> b < 10, 14)
Not a big deal, but your question made me curious...

You could reduce your xor'ed predicates to a single predicate with stream.reduce and then return the outcome.
like so:
import java.util.function.Predicate;
import java.util.Arrays;
public class MultiXor{
public static void main(String[] args){
System.out.println(xor("monkey", p -> p.equals("monkey"), p -> p.equals("dork"), p -> p.equalsIgnoreCase("Monkey")) );
System.out.println(true ^ false ^ true);
System.out.println(xor("monkey", p -> p.equals("monkey"), p -> p.equals("dork")) );
System.out.println(true ^ false);
}
public static <T> boolean xor(final T param, Predicate<T>... predicates){
return Arrays.stream(predicates).reduce( p -> false, (previous, p) -> r -> previous.test(param) ^ (p.test(param))).test(param);
}
}

Related

Stream iterate not using last value

Simplified Example
I have the following code which generates the sum of a series i.e. 1, 1+2, 1+2+3, 1+2+3+4
public static void main(String[] args) {
Stream<Integer> inputStream = Stream.of(1,2,3,4);
Iterator<Integer> iterator = inputStream.iterator();
Stream<Integer> outputStream = Stream.iterate(
iterator.next(),
i -> iterator.hasNext(),
next -> {
return iterator.next() + next;
}
);
List<Integer> outputList = outputStream.collect(Collectors.toList());
System.out.println(outputList);
}
But this prints: [1, 3, 6], missing the last element.
Working example but needs Atomic Variable
Note this seems to get the correct check I want, but is there a better solution? Looks awful:
public static void main(String[] args) {
Stream<Integer> inputStream = Stream.of(1,2,3,4);
Iterator<Integer> iterator = inputStream.iterator();
AtomicBoolean check = new AtomicBoolean(true);
Stream<Integer> outputStream = Stream.iterate(
iterator.next(),
i -> check.get(),
next -> {
check.set(iterator.hasNext());
return iterator.hasNext() ? iterator.next() + next : next;
}
);
List<Integer> outputList = outputStream.collect(Collectors.toList());
System.out.println(outputList);
}
Generic Problem description
Here's a generic code illustrating the problem.
public static <O, I> Stream<O> iterate(O seed, Stream<I> stream, BiFunction<I,O,O> function) {
return iterate(seed, stream.iterator(), function);
}
public static <O, I> Stream<O> iterate(O seed, Iterator<I> iterator, BiFunction<I,O,O> function) {
AtomicBoolean hasNext = new AtomicBoolean(true);
return Stream.iterate(
seed,
i -> hasNext.get(),
next -> {
hasNext.set(iterator.hasNext());
return iterator.hasNext() ? function.apply(iterator.next(), next) : next;
}
);
}
public static void main(String[] args) {
Stream<Integer> inputStream = Stream.of(2,3,4);
BiFunction<Integer, Integer, Integer> f = Integer::sum;
Stream<Integer> outputStream = iterate(1, inputStream, f);
List<Integer> outputList = outputStream.collect(Collectors.toList());
System.out.println(outputList);
}
Problem Context
Basically, I want to do this because I am creating a function which produces a forecast of the balance of an interest bearing account.
I want to be able to take a stream of dates and then produce a stream of balances. That way you don't need to know how many elements there will be, or even the distribution of dates, which makes it a more flexible approach.
Also note that the next element of the Stream depends on the previous. This is why I have a seed which represents the first value (does not have a previous value), which would be the opening balance.
... but is there a better solution?
Yes, an elegant solution can be by using Arrays#parallelPrefix.
public class Main {
public static void main(String args[]) {
int[] arr = { 1, 2, 3, 4 };
Arrays.parallelPrefix(arr, Integer::sum);
System.out.println(Arrays.toString(arr));
}
}
Output:
[1, 3, 6, 10]
You can always convert back and forth between Stream<Integer> and int[] as per your requirement.
public class Main {
public static void main(String args[]) {
int[] arr = Stream.of(1, 2, 3, 4).mapToInt(Integer::valueOf).toArray();
Arrays.parallelPrefix(arr, Integer::sum);
System.out.println(Arrays.toString(arr));
// In case , you need a Stream<Integer> again
Stream<Integer> resultStream = Arrays.stream(arr).boxed();
// Or want the result as a List<Integer>
List<Integer> resultList = resultStream.toList();
System.out.println(resultList);
}
}
The problem is that the three arguments to Stream.iterate(…,…,…) correspond to the three arguments to a for(…;…;…) … statement, where the loop’s body corresponds to the chained stream operations. But this doesn’t match an iterator loop, which looks like
for(Iterator<I> iterator = …; iterator.hasNext(); ) {
I elements = iterator.next();
…
}
In other words, the right place of the next() call would be after the hasNext() check, before the remaining loop body, whereas the function passed as third argument to Stream.iterate(…,…,…) is evaluated after the loop body equivalent, before the hasNext() check.
A simple solution would be
public static <O, I> Stream<O> iterate(
O seed, Iterator<I> iterator, BiFunction<I,O,O> function) {
return Stream.iterate(seed, Objects::nonNull,
prev -> iterator.hasNext()? function.apply(iterator.next(), prev): null);
}
which effectively moves the hasNext() check before the next() call. But it requires that null will never occur as a normal result of the function evaluation, which should be the case for all arithmetic operations.
Otherwise, you would have to go one level deeper to implement a general-purpose stream operation:
public static <O, I> Stream<O> iterate(
O seed, Stream<I> stream, BiFunction<I,O,O> function) {
boolean parallel = stream.isParallel();
Spliterator<I> sp = stream.spliterator();
return StreamSupport.stream(new Spliterators.AbstractSpliterator<O>(
sp.estimateSize() == Long.MAX_VALUE? Long.MAX_VALUE: sp.estimateSize() + 1,
sp.characteristics() & Spliterator.SIZED | Spliterator.ORDERED) {
O value = seed;
final Consumer<I> c = i -> value = function.apply(i, value);
boolean end;
#Override
public boolean tryAdvance(Consumer<? super O> action) {
if(end) return false;
O current = value;
end = !sp.tryAdvance(c);
action.accept(current);
return true;
}
}, parallel).onClose(stream::close);
}
This is more complicated, but has no constraints of the values produced by the function and is more efficient than going through an Iterator. Note that this solution also cares to retain the current parallel setting and ensures that closing the stream will be delegated to the original stream, which might be important when being backed by a resource, like Files.lines, etc.
Try this:
AtomicInteger sum = new AtomicInteger(0);
List<Integer> result = Stream.of(1, 2, 3, 4).map(it -> sum.addAndGet(it)).toList();
result.forEach(System.out::print);
Here's a generic code illustrating the problem.
public static <O, I> Stream<O> iterate(O seed, Stream<I> stream,
BiFunction<I,O,O> function) {
return iterate(seed, stream.iterator(), function);
}
I want to be able to take a stream of dates and then produce a stream
of balances. That way you don't need to know how many elements there
will be, or even the distribution of dates, which makes it a more
flexible approach.
I've written the following solution based on the assumption that it's possible to merge the balances produces in the different threads, and the function BiFunction<I,O,O> is associative, as well as a merging function BinaryOperator<O>, that would be responsible for combining resulting values, i.e. balances.
Also, the value of seed should meat the same requirements which are imposed on identity of the Stream.reduce() operation (otherwise parallel stream would yield an incorrect result). I.e.
merger.apply(r, mapper.apply(seed, t)) == mapper.apply(t, r)
Which would not hold true if seed would be 1 and both mapper and merger would be defined as Integer::sum, but i -> i * i and seed 1 the condition would be met.
Note that if at least one of these requirements is not possible to fulfil, streams are not the right tool for this problem.
Here's how it might be implemented using a custom Collector. To define a Collector we can use static method Collector.of().
public static <R, T> Stream<R> iterate(R seed, Stream<T> stream,
BiFunction<T, R, R> mapper,
BinaryOperator<R> merger) {
return stream
.collect(sequenceCollector(seed, mapper, merger));
}
public static <R, T> Collector<T, ?, Stream<R>> sequenceCollector(R seed,
BiFunction<T, R, R> mapper,
BinaryOperator<R> merger) {
return Collector.of(
ArrayDeque::new,
(Deque<R> deque, T next) ->
deque.add(
mapper.apply(next, Objects.requireNonNullElse(deque.peekLast(), seed))
),
(left, right) -> {
R last = left.getLast();
right.forEach(next -> left.add(merger.apply(next, last)));
return left;
},
Collection::stream
);
}
main()
public static void main(String[] args) {
Stream<Integer> input1 = Stream.of(1, 2, 3, 4);
Stream<Integer> output1 = iterate(0, input1, Integer::sum, Integer::sum);
List<Integer> outputList1 = output1.toList();
System.out.println("Sequential: " + outputList1);
Stream<Integer> input2 = Stream.of(1, 2, 3, 4).parallel();
Stream<Integer> output2 = iterate(0, input2, Integer::sum, Integer::sum);
List<Integer> outputList2 = output2.toList();
System.out.println("Parallel: " + outputList2);
}
Output:
Sequential: [1, 3, 6, 10]
Parallel: [1, 3, 6, 10]

Java 8 forEach applied to only some?

No "if" statements, please, unless you're explaining why it's impossible to do without one.
I'm seeing how far I can go operating on streams only. I have this nuisance:
List<Cube> revised =
cubes.filter(p)
.map(c -> f(c))
.map(c -> {
if(c.prop()) {
c.addComment(comment);
}
return c;
})
.collect(Collectors.toList());
My best idea for how to do this without an "if" is
List<Cube> revised =
cubes.filter(p)
.map(c -> f(c));
revised
.filter(Cube::prop)
.forEach(c -> c.addComment(comment)); // can also map still
Is there a way to do this in one chain only? A branch basically has to happen in the stream if so. A method like forSome(predicate, lambda) would work.
Do not want to "roll my own" anything. I can use an "if" but I'm trying to learn how expressive functional style can be.
There's no need to use map that returns the same element, when you have peek. The following code "cheats" by using a short-circuit operator:
cubes.filter(p)
.map(c -> f(c))
.peek(c -> c.prop() && c.addComment(comment))
I think the "modern" way using Optional is far less readable:
cubes.filter(p)
.map(c -> f(c))
.peek(c -> Optional.of(c).filter(Cube::prop).ifPresent(c -> c.addComment(comment)))
You can implement your forSome function in following way:
public static <T> T forSome(T c, Predicate<T> condition, Consumer<T> extraBehaviour) {
if (condition.test(c)) {
extraBehaviour.accept(c);
}
return c;
}
Than you can use map operator to inject this into stream:
List<Cube> revised = cubes.stream().filter(p)
.map(c -> f(c))
.map(c -> forSome(c, Cube::prop, cube -> cube.addComment("my comment 2")))
.collect(Collectors.toList());
Just to give another example of usage we can take following example:
class StudentExam {
private final String studentName;
private final List<Character> answers;
private boolean passed = false;
StudentExam(String studentName, List<Character> answers) {
this.studentName = studentName;
this.answers = answers;
}
public void markAsPassed() {
this.passed = true;
}
public boolean isPassed() {
return passed;
}
public Character getAnswer(int index) {
return answers.get(index);
}
public String getStudentName() {
return studentName;
}
}
List<StudentExam> results = asList(
new StudentExam("John", asList(new Character[] {'A', 'B'})),
new StudentExam("Andy", asList(new Character[] {'A', 'C'})),
new StudentExam("Mary", asList(new Character[] {'B', 'B'})),
new StudentExam("Jane", asList(new Character[] {'C', 'D'}))
);
Now we can if correct answers are 'A' and 'B' than we can stream through the objects and set the appropriate status of exam.
results.stream()
.map(examResult -> forSome(
examResult,
er -> er.getAnswer(0).equals('A') || er.getAnswer(1).equals('B'),
StudentExam::markAsPassed))
.forEach(studentExam ->
studentExam.getStudentName() + " passed: " + studentExam.isPassed()));
prints:
John: passed true
Andy: passed true
Mary: passed true
Jane: passed false

How to combine 3 or more CompletionStages?

If have 2 CompletionStages, I can combine them with thenCombine method:
CompletionStage<A> aCompletionStage = getA();
CompletionStage<B> bCompletionStage = getB();
CompletionStage<Combined> combinedCompletionStage =
aCompletionStage.thenCombine(bCompletionStage, (aData, bData) -> combine(aData, bData));
If I have 3 or more CompletionStages, I can make a chain of thenCombine methods, but I have to use temporary objects to pass results. For example, here is a solution using Pair and Triple from the org.apache.commons.lang3.tuple package:
CompletionStage<A> aCompletionStage = getA();
CompletionStage<B> bCompletionStage = getB();
CompletionStage<C> cCompletionStage = getC();
CompletionStage<D> dCompletionStage = getD();
CompletionStage<Combined> combinedDataCompletionStage =
aCompletionStage.thenCombine(bCompletionStage, (Pair::of))
.thenCombine(cCompletionStage, (ab, c) ->
Triple.of(ab.getLeft(), ab.getRight(), c))
.thenCombine(dCompletionStage, (abc, d) ->
combine(abc.getLeft(), abc.getMiddle(), abc.getRight(), d));
Is there a better way to combine results from multiple CompletionStages?
The only way to combine multiple stages that scales well with a growing number of stages, is to use CompletableFuture. If your CompletionStages aren’t CompletableFutures you may still convert them using .toCompletableFuture():
CompletableFuture<A> aCompletionStage = getA().toCompletableFuture();
CompletableFuture<B> bCompletionStage = getB().toCompletableFuture();
CompletableFuture<C> cCompletionStage = getC().toCompletableFuture();
CompletableFuture<D> dCompletionStage = getD().toCompletableFuture();
CompletionStage<Combined> combinedDataCompletionStage = CompletableFuture.allOf(
aCompletionStage, bCompletionStage, cCompletionStage, dCompletionStage)
.thenApply(ignoredVoid -> combine(
aCompletionStage.join(), bCompletionStage.join(),
cCompletionStage.join(), dCompletionStage.join()) );
This contains more boilerplate than combining two stages via thenCombine but the boilerplate doesn’t grow when adding more stages to it.
Note that even with your original thenCombine approach, you don’t need a Triple, a Pair is sufficient:
CompletionStage<Combined> combinedDataCompletionStage =
aCompletionStage.thenCombine(bCompletionStage, (Pair::of)).thenCombine(
cCompletionStage.thenCombine(dCompletionStage, Pair::of),
(ab, cd) -> combine(ab.getLeft(), ab.getRight(), cd.getLeft(), cd.getRight()));
Still, it doesn’t scale well if you want to combine more stages.
An in-between solution (regarding complexity) might be:
CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
a -> bCompletionStage.thenCompose(b -> cCompletionStage.thenCompose(
c -> dCompletionStage.thenApply(d -> combine(a, b, c, d)))));
That’s simpler in its structure but still doesn’t scale well with more more stages.
Holger's third answer can be made a little bit shorter:
CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
a -> bCompletionStage.thenCompose(
b -> cCompletionStage.thenCombine(dCompletionStage,
(c, d) -> combine(a, b, c, d))));
You asked about "3 or more", if you have them in a List as CompletableFutures (see other answers) you could use this handy method:
private static <T> CompletableFuture<List<T>> join(List<CompletableFuture<T>> executionPromises) {
CompletableFuture<Void> joinedPromise = CompletableFuture.allOf(executionPromises.toArray(CompletableFuture[]::new));
return joinedPromise.thenApply(voit -> executionPromises.stream().map(CompletableFuture::join).collect(Collectors.toList()));
}
It converts your "list of futures" to a "future for a list of the results".
Any number of CompletableFuture can be combined (reduced)
CompletionStage<A> futA = getA();
CompletionStage<B> futB = getB();
CompletionStage<C> futC = getC();
Stream.of(futA, futB, futC)
.reduce((f1, f2) -> f1.thenCombine(f2, (d1, d2) -> combine(d1, d2));
The implementation of combine method will be responsible to merge data values (A, B and C), which could be tricky if A, B and C are disparate.
I think you should use an intermediary object, but one of your own instead of using Pair and Tuple
public R method() {
CompletableFuture<A> aFuture = getAFuture();
CompletableFuture<B> bFuture = getBFuture();
CompletableFuture<C> cFuture = getCFuture();
CompletableFuture<D> dFuture = getDFuture();
return CompletableFuture.completedFuture(new WellNamedResultHolder())
.thenCombineAsync(aFuture, WellNamedResultHolder::withAResult)
.thenCombineAsync(bFuture, WellNamedResultHolder::withBResult)
.thenCombineAsync(cFuture, WellNamedResultHolder::withCResult)
.thenCombineAsync(dFuture, WellNamedResultHolder::withDResult)
.thenApplyAsync(this::combineAllTheResults);
}
private static class WellNamedResultHolder {
private A aResult;
private B bResult;
private C cResult;
private D dResult;
// Getters
public WellNamedResultHolder withAResult(final A aResult) {
this.aResult = aResult;
return this;
}
public WellNamedResultHolder withBResult(final B bResult) {
this.bResult = bResult;
return this;
}
public WellNamedResultHolder withCResult(final C cResult) {
this.cResult = cResult;
return this;
}
public WellNamedResultHolder withDResult(final D dResult) {
this.dResult = dResult;
return this;
}
}
The actual form of the result holder can obviously change to match your own needs, giving you greater flexibility. You also get to be in charge of what happens as these futures complete. Although there is more boilerplate, you get code that is more descriptive of what is happening (which lombok can tidy up).
I had a similar problem but had more than 3 completablefutures so building up on Holger's answer I made a small generic utility.
public static <T, R> CompletableFuture<R> allOf(List<CompletableFuture<T>> args, Function<List<T>, R> combiner) {
final Queue<CompletableFuture<T>> queue = new LinkedList<>();
for (CompletableFuture<T> arg : args) {
queue.add(arg);
}
return aggregator(queue, new ArrayList<>(), combiner);
}
private static <T, R> CompletableFuture<R> aggregator(Queue<CompletableFuture<T>> queue, List<T> arg,
Function<List<T>, R> combiner) {
if (queue.size() == 2)
return queue.poll().thenCombine(queue.poll(), (c, d) -> {
arg.add(c);
arg.add(d);
return combiner.apply(arg);
});
return queue.poll().thenCompose(data -> {
arg.add(data);
return aggregator(queue, arg, combiner);
});
}
I think that CompleableFuture.allOf() function can help you.
For example: (View full Class here)
List<String> urls = [
"https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994",
"https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994?a=1"
]
CompletableFuture<Response>[] futures = new Completablefuture[2]
for (int i = 0; i < urls.size(); i++) {
futures[i] = asyncHttpClient.prepareGet(urls[i]).execute().toCompletableFuture()
}
CompletableFuture.allOf(futures).thenApply { future ->
return futures.collect { it.join() }
}.thenApply({ responses ->
//Do something with results
responses.each { println("Status code: " + it.statusCode) }
})
You can create a helper function...
combine3(
futureA, futureB, futureC,
(a, b, c) -> {
// let's go!
}).toCompletableFuture();
Definition:
private static <A, B, C, D> CompletionStage<D> combine3(
CompletionStage<A> aStage,
CompletionStage<B> bStage,
CompletionStage<C> cStage,
TriFunction<A, B, C, D> f
) {
return aStage.thenCompose(
a -> bStage.thenCombine(cStage,
(b, c) -> f.apply(a, b, c)));
}
interface TriFunction<A, B, C, D> {
D apply(A a, B b, C c);
}
I had the exact same problem (and likewise for Optional) so I wrote a library to generate thenCombine-methods up to arity 26: https://github.com/wernerdegroot/applicatives
Perhaps it will be of help.
If you want to combine results from multiple CFs you need an aggregator for that.
Take a look on the following example, on how to combine multiple CFs returning strings:
public static void main(String[] args) throws ExecutionException, InterruptedException {
var executor = CompletableFuture.delayedExecutor(10, TimeUnit.SECONDS);
var cf1 = CompletableFuture.supplyAsync(() -> "1", executor);
var cf2 = CompletableFuture.supplyAsync(() -> "2", executor);
var cf3 = CompletableFuture.supplyAsync(() -> "3", executor);
var cf4 = CompletableFuture.supplyAsync(() -> "4", executor);
var collectees = List.of(cf1, cf2, cf3, cf4);
System.out.println(Instant.now() + ": before combine");
var combinedFuture = combine(collectees);
System.out.println(Instant.now() + ": after combine");
// .get() is a blocking function
// if you remove .get() the program will print uncompleted future and exit (e.g. works async)
var result = combinedFuture.thenApply(list -> String.join(" - ", list)).get();
System.out.println(Instant.now() + ": " + result);
}
static <T> CompletableFuture<? extends List<T>> combine(List<CompletableFuture<T>> input) {
var collector = CompletableFuture.completedFuture(new ArrayList<T>(input.size()));
for (var toCollect : input) {
collector = collector.thenCombine(toCollect, (ts, t) -> {
ts.add(t);
return ts;
});
}
return collector;
}

Get reverse of predicate when Filtering?

I know the basics of predicates and understand below code copied from this question
Predicate<Integer> isEven = new Predicate<Integer>() {
#Override public boolean apply(Integer number) {
return (number % 2) == 0;
}
};
Iterable<Integer> evenNumbers = Iterables.filter(numbers, isEven);
But is it possible to get an iterable for the items that did not match the predicate (without changing the predicate code)?
Use Predicates#not(Predicate).
Iterable<Integer> oddNumbers = Iterables.filter(numbers, Predicates.not(isEven));
You can try:
removeIf(Iterable, Predicate) --> Removes all elements satisfying the predicate, using the Iterator.remove() method.
Iterators.removeIf(Iterator, Predicate)
Can find more information here.

Java 8 stream reverse order

General question: What's the proper way to reverse a stream? Assuming that we don't know what type of elements that stream consists of, what's the generic way to reverse any stream?
Specific question:
IntStream provides range method to generate Integers in specific range IntStream.range(-range, 0), now that I want to reverse it switching range from 0 to negative won't work, also I can't use Integer::compare
List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);
with IntStream I'll get this compiler error
Error:(191, 0) ajc: The method sorted() in the type IntStream is not applicable for the arguments (Integer::compare)
what am I missing here?
For the specific question of generating a reverse IntStream, try something like this:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to)
.map(i -> to - i + from - 1);
}
This avoids boxing and sorting.
For the general question of how to reverse a stream of any type, I don't know of there's a "proper" way. There are a couple ways I can think of. Both end up storing the stream elements. I don't know of a way to reverse a stream without storing the elements.
This first way stores the elements into an array and reads them out to a stream in reverse order. Note that since we don't know the runtime type of the stream elements, we can't type the array properly, requiring an unchecked cast.
#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]);
}
Another technique uses collectors to accumulate the items into a reversed list. This does lots of insertions at the front of ArrayList objects, so there's lots of copying going on.
Stream<T> input = ... ;
List<T> output =
input.collect(ArrayList::new,
(list, e) -> list.add(0, e),
(list1, list2) -> list1.addAll(0, list2));
It's probably possible to write a much more efficient reversing collector using some kind of customized data structure.
UPDATE 2016-01-29
Since this question has gotten a bit of attention recently, I figure I should update my answer to solve the problem with inserting at the front of ArrayList. This will be horribly inefficient with a large number of elements, requiring O(N^2) copying.
It's preferable to use an ArrayDeque instead, which efficiently supports insertion at the front. A small wrinkle is that we can't use the three-arg form of Stream.collect(); it requires the contents of the second arg be merged into the first arg, and there's no "add-all-at-front" bulk operation on Deque. Instead, we use addAll() to append the contents of the first arg to the end of the second, and then we return the second. This requires using the Collector.of() factory method.
The complete code is this:
Deque<String> output =
input.collect(Collector.of(
ArrayDeque::new,
(deq, t) -> deq.addFirst(t),
(d1, d2) -> { d2.addAll(d1); return d2; }));
The result is a Deque instead of a List, but that shouldn't be much of an issue, as it can easily be iterated or streamed in the now-reversed order.
Elegant solution
List<Integer> list = Arrays.asList(1,2,3,4);
list.stream()
.sorted(Collections.reverseOrder()) // Method on Stream<Integer>
.forEach(System.out::println);
General Question:
Stream does not store any elements.
So iterating elements in the reverse order is not possible without storing the elements in some intermediate collection.
Stream.of("1", "2", "20", "3")
.collect(Collectors.toCollection(ArrayDeque::new)) // or LinkedList
.descendingIterator()
.forEachRemaining(System.out::println);
Update: Changed LinkedList to ArrayDeque (better) see here for details
Prints:
3
20
2
1
By the way, using sort method is not correct as it sorts, NOT reverses (assuming stream may have unordered elements)
Specific Question:
I found this simple, easier and intuitive(Copied #Holger comment)
IntStream.iterate(to - 1, i -> i - 1).limit(to - from)
Many of the solutions here sort or reverse the IntStream, but that unnecessarily requires intermediate storage. Stuart Marks's solution is the way to go:
static IntStream revRange(int from, int to) {
return IntStream.range(from, to).map(i -> to - i + from - 1);
}
It correctly handles overflow as well, passing this test:
#Test
public void testRevRange() {
assertArrayEquals(revRange(0, 5).toArray(), new int[]{4, 3, 2, 1, 0});
assertArrayEquals(revRange(-5, 0).toArray(), new int[]{-1, -2, -3, -4, -5});
assertArrayEquals(revRange(1, 4).toArray(), new int[]{3, 2, 1});
assertArrayEquals(revRange(0, 0).toArray(), new int[0]);
assertArrayEquals(revRange(0, -1).toArray(), new int[0]);
assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE).toArray(), new int[0]);
assertArrayEquals(revRange(MAX_VALUE, MAX_VALUE).toArray(), new int[0]);
assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE + 1).toArray(), new int[]{MIN_VALUE});
assertArrayEquals(revRange(MAX_VALUE - 1, MAX_VALUE).toArray(), new int[]{MAX_VALUE - 1});
}
How NOT to do it:
Don't use .sorted(Comparator.reverseOrder()) or .sorted(Collections.reverseOrder()), because it will just sort elements in the descending order.
Using it for given Integer input:
[1, 4, 2, 5, 3]
the output would be as follows:
[5, 4, 3, 2, 1]
For String input:
["A", "D", "B", "E", "C"]
the output would be as follows:
[E, D, C, B, A]
Don't use .sorted((a, b) -> -1) (explanation at the end)
The easiest way to do it properly:
List<Integer> list = Arrays.asList(1, 4, 2, 5, 3);
Collections.reverse(list);
System.out.println(list);
Output:
[3, 5, 2, 4, 1]
The same for String:
List<String> stringList = Arrays.asList("A", "D", "B", "E", "C");
Collections.reverse(stringList);
System.out.println(stringList);
Output:
[C, E, B, D, A]
Don't use .sorted((a, b) -> -1)!
It breaks comparator contract and might work only for some cases ie. only on single thread but not in parallel.
yankee explanation:
(a, b) -> -1 breaks the contract for Comparator. Whether this works depends on the implementation of the sort algorithm. The next release of the JVM might break this. Actually I can already break this reproduciblly on my machine using IntStream.range(0, 10000).parallel().boxed().sorted((a, b) -> -1).forEachOrdered(System.out::println);
//Don't use this!!!
List<Integer> list = Arrays.asList(1, 4, 2, 5, 3);
List<Integer> reversedList = list.stream()
.sorted((a, b) -> -1)
.collect(Collectors.toList());
System.out.println(reversedList);
Output in positive case:
[3, 5, 2, 4, 1]
Possible output in parallel stream or with other JVM implementation:
[4, 1, 2, 3, 5]
The same for String:
//Don't use this!!!
List<String> stringList = Arrays.asList("A", "D", "B", "E", "C");
List<String> reversedStringList = stringList.stream()
.sorted((a, b) -> -1)
.collect(Collectors.toList());
System.out.println(reversedStringList);
Output in positive case:
[C, E, B, D, A]
Possible output in parallel stream or with other JVM implementation:
[A, E, B, D, C]
without external lib...
import java.util.List;
import java.util.Collections;
import java.util.stream.Collector;
public class MyCollectors {
public static <T> Collector<T, ?, List<T>> toListReversed() {
return Collectors.collectingAndThen(Collectors.toList(), l -> {
Collections.reverse(l);
return l;
});
}
}
If implemented Comparable<T> (ex. Integer, String, Date), you can do it using Comparator.reverseOrder().
List<Integer> list = Arrays.asList(1, 2, 3, 4);
list.stream()
.sorted(Comparator.reverseOrder())
.forEach(System.out::println);
You could define your own collector that collects the elements in reverse order:
public static <T> Collector<T, List<T>, List<T>> inReverse() {
return Collector.of(
ArrayList::new,
(l, t) -> l.add(t),
(l, r) -> {l.addAll(r); return l;},
Lists::<T>reverse);
}
And use it like:
stream.collect(inReverse()).forEach(t -> ...)
I use an ArrayList in forward order to efficiently insert collect the items (at the end of the list), and Guava Lists.reverse to efficiently give a reversed view of the list without making another copy of it.
Here are some test cases for the custom collector:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import org.hamcrest.Matchers;
import org.junit.Test;
import com.google.common.collect.Lists;
public class TestReverseCollector {
private final Object t1 = new Object();
private final Object t2 = new Object();
private final Object t3 = new Object();
private final Object t4 = new Object();
private final Collector<Object, List<Object>, List<Object>> inReverse = inReverse();
private final Supplier<List<Object>> supplier = inReverse.supplier();
private final BiConsumer<List<Object>, Object> accumulator = inReverse.accumulator();
private final Function<List<Object>, List<Object>> finisher = inReverse.finisher();
private final BinaryOperator<List<Object>> combiner = inReverse.combiner();
#Test public void associative() {
final List<Object> a1 = supplier.get();
accumulator.accept(a1, t1);
accumulator.accept(a1, t2);
final List<Object> r1 = finisher.apply(a1);
final List<Object> a2 = supplier.get();
accumulator.accept(a2, t1);
final List<Object> a3 = supplier.get();
accumulator.accept(a3, t2);
final List<Object> r2 = finisher.apply(combiner.apply(a2, a3));
assertThat(r1, Matchers.equalTo(r2));
}
#Test public void identity() {
final List<Object> a1 = supplier.get();
accumulator.accept(a1, t1);
accumulator.accept(a1, t2);
final List<Object> r1 = finisher.apply(a1);
final List<Object> a2 = supplier.get();
accumulator.accept(a2, t1);
accumulator.accept(a2, t2);
final List<Object> r2 = finisher.apply(combiner.apply(a2, supplier.get()));
assertThat(r1, equalTo(r2));
}
#Test public void reversing() throws Exception {
final List<Object> a2 = supplier.get();
accumulator.accept(a2, t1);
accumulator.accept(a2, t2);
final List<Object> a3 = supplier.get();
accumulator.accept(a3, t3);
accumulator.accept(a3, t4);
final List<Object> r2 = finisher.apply(combiner.apply(a2, a3));
assertThat(r2, contains(t4, t3, t2, t1));
}
public static <T> Collector<T, List<T>, List<T>> inReverse() {
return Collector.of(
ArrayList::new,
(l, t) -> l.add(t),
(l, r) -> {l.addAll(r); return l;},
Lists::<T>reverse);
}
}
cyclops-react StreamUtils has a reverse Stream method (javadoc).
StreamUtils.reverse(Stream.of("1", "2", "20", "3"))
.forEach(System.out::println);
It works by collecting to an ArrayList and then making use of the ListIterator class which can iterate in either direction, to iterate backwards over the list.
If you already have a List, it will be more efficient
StreamUtils.reversedStream(Arrays.asList("1", "2", "20", "3"))
.forEach(System.out::println);
Here's the solution I've come up with:
private static final Comparator<Integer> BY_ASCENDING_ORDER = Integer::compare;
private static final Comparator<Integer> BY_DESCENDING_ORDER = BY_ASCENDING_ORDER.reversed();
then using those comparators:
IntStream.range(-range, 0).boxed().sorted(BY_DESCENDING_ORDER).forEach(// etc...
I would suggest using jOOλ, it's a great library that adds lots of useful functionality to Java 8 streams and lambdas.
You can then do the following:
List<Integer> list = Arrays.asList(1,2,3,4);
Seq.seq(list).reverse().forEach(System.out::println)
Simple as that. It's a pretty lightweight library, and well worth adding to any Java 8 project.
How about this utility method?
public static <T> Stream<T> getReverseStream(List<T> list) {
final ListIterator<T> listIt = list.listIterator(list.size());
final Iterator<T> reverseIterator = new Iterator<T>() {
#Override
public boolean hasNext() {
return listIt.hasPrevious();
}
#Override
public T next() {
return listIt.previous();
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
reverseIterator,
Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
}
Seems to work with all cases without duplication.
With regard to the specific question of generating a reverse IntStream:
starting from Java 9 you can use the three-argument version of the IntStream.iterate(...):
IntStream.iterate(10, x -> x >= 0, x -> x - 1).forEach(System.out::println);
// Out: 10 9 8 7 6 5 4 3 2 1 0
where:
IntStream.iterate​(int seed, IntPredicate hasNext, IntUnaryOperator next);
seed - the initial element;
hasNext - a predicate to apply to elements to determine when the
stream must terminate;
next - a function to be applied to the previous element to produce a
new element.
Simplest way (simple collect - supports parallel streams):
public static <T> Stream<T> reverse(Stream<T> stream) {
return stream
.collect(Collector.of(
() -> new ArrayDeque<T>(),
ArrayDeque::addFirst,
(q1, q2) -> { q2.addAll(q1); return q2; })
)
.stream();
}
Advanced way (supports parallel streams in an ongoing way):
public static <T> Stream<T> reverse(Stream<T> stream) {
Objects.requireNonNull(stream, "stream");
class ReverseSpliterator implements Spliterator<T> {
private Spliterator<T> spliterator;
private final Deque<T> deque = new ArrayDeque<>();
private ReverseSpliterator(Spliterator<T> spliterator) {
this.spliterator = spliterator;
}
#Override
#SuppressWarnings({"StatementWithEmptyBody"})
public boolean tryAdvance(Consumer<? super T> action) {
while(spliterator.tryAdvance(deque::addFirst));
if(!deque.isEmpty()) {
action.accept(deque.remove());
return true;
}
return false;
}
#Override
public Spliterator<T> trySplit() {
// After traveling started the spliterator don't contain elements!
Spliterator<T> prev = spliterator.trySplit();
if(prev == null) {
return null;
}
Spliterator<T> me = spliterator;
spliterator = prev;
return new ReverseSpliterator(me);
}
#Override
public long estimateSize() {
return spliterator.estimateSize();
}
#Override
public int characteristics() {
return spliterator.characteristics();
}
#Override
public Comparator<? super T> getComparator() {
Comparator<? super T> comparator = spliterator.getComparator();
return (comparator != null) ? comparator.reversed() : null;
}
#Override
public void forEachRemaining(Consumer<? super T> action) {
// Ensure that tryAdvance is called at least once
if(!deque.isEmpty() || tryAdvance(action)) {
deque.forEach(action);
}
}
}
return StreamSupport.stream(new ReverseSpliterator(stream.spliterator()), stream.isParallel());
}
Note you can quickly extends to other type of streams (IntStream, ...).
Testing:
// Use parallel if you wish only
revert(Stream.of("One", "Two", "Three", "Four", "Five", "Six").parallel())
.forEachOrdered(System.out::println);
Results:
Six
Five
Four
Three
Two
One
Additional notes: The simplest way it isn't so useful when used with other stream operations (the collect join breaks the parallelism). The advance way doesn't have that issue, and it keeps also the initial characteristics of the stream, for example SORTED, and so, it's the way to go to use with other stream operations after the reverse.
ArrayDeque are faster in the stack than a Stack or LinkedList. "push()" inserts elements at the front of the Deque
protected <T> Stream<T> reverse(Stream<T> stream) {
ArrayDeque<T> stack = new ArrayDeque<>();
stream.forEach(stack::push);
return stack.stream();
}
List newStream = list.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList());
newStream.forEach(System.out::println);
One could write a collector that collects elements in reversed order:
public static <T> Collector<T, ?, Stream<T>> reversed() {
return Collectors.collectingAndThen(Collectors.toList(), list -> {
Collections.reverse(list);
return list.stream();
});
}
And use it like this:
Stream.of(1, 2, 3, 4, 5).collect(reversed()).forEach(System.out::println);
Original answer (contains a bug - it does not work correctly for parallel streams):
A general purpose stream reverse method could look like:
public static <T> Stream<T> reverse(Stream<T> stream) {
LinkedList<T> stack = new LinkedList<>();
stream.forEach(stack::push);
return stack.stream();
}
For reference I was looking at the same problem, I wanted to join the string value of stream elements in the reverse order.
itemList = { last, middle, first } => first,middle,last
I started to use an intermediate collection with collectingAndThen from comonad or the ArrayDeque collector of Stuart Marks, although I wasn't happy with intermediate collection, and streaming again
itemList.stream()
.map(TheObject::toString)
.collect(Collectors.collectingAndThen(Collectors.toList(),
strings -> {
Collections.reverse(strings);
return strings;
}))
.stream()
.collect(Collector.joining());
So I iterated over Stuart Marks answer that was using the Collector.of factory, that has the interesting finisher lambda.
itemList.stream()
.collect(Collector.of(StringBuilder::new,
(sb, o) -> sb.insert(0, o),
(r1, r2) -> { r1.insert(0, r2); return r1; },
StringBuilder::toString));
Since in this case the stream is not parallel, the combiner is not relevant that much, I'm using insert anyway for the sake of code consistency but it does not matter as it would depend of which stringbuilder is built first.
I looked at the StringJoiner, however it does not have an insert method.
Not purely Java8 but if you use guava's Lists.reverse() method in conjunction, you can easily achieve this:
List<Integer> list = Arrays.asList(1,2,3,4);
Lists.reverse(list).stream().forEach(System.out::println);
Reversing string or any Array
(Stream.of("abcdefghijklm 1234567".split("")).collect(Collectors.collectingAndThen(Collectors.toList(),list -> {Collections.reverse(list);return list;}))).stream().forEach(System.out::println);
split can be modified based on the delimiter or space
How about reversing the Collection backing the stream prior?
import java.util.Collections;
import java.util.List;
public void reverseTest(List<Integer> sampleCollection) {
Collections.reverse(sampleCollection); // remember this reverses the elements in the list, so if you want the original input collection to remain untouched clone it first.
sampleCollection.stream().forEach(item -> {
// you op here
});
}
Answering specific question of reversing with IntStream, below worked for me:
IntStream.range(0, 10)
.map(x -> x * -1)
.sorted()
.map(Math::abs)
.forEach(System.out::println);
In all this I don't see the answer I would go to first.
This isn't exactly a direct answer to the question, but it's a potential solution to the problem.
Just build the list backwards in the first place. If you can, use a LinkedList instead of an ArrayList and when you add items use "Push" instead of add. The list will be built in the reverse order and will then stream correctly without any manipulation.
This won't fit cases where you are dealing with primitive arrays or lists that are already used in various ways but does work well in a surprising number of cases.
the simplest solution is using List::listIterator and Stream::generate
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
ListIterator<Integer> listIterator = list.listIterator(list.size());
Stream.generate(listIterator::previous)
.limit(list.size())
.forEach(System.out::println);
This method works with any Stream and is Java 8 compliant:
Stream<Integer> myStream = Stream.of(1, 2, 3, 4, 5);
myStream.reduce(Stream.empty(),
(Stream<Integer> a, Integer b) -> Stream.concat(Stream.of(b), a),
(a, b) -> Stream.concat(b, a))
.forEach(System.out::println);
This is how I do it.
I don't like the idea of creating a new collection and reverse iterating it.
The IntStream#map idea is pretty neat, but I prefer the IntStream#iterate method, for I think the idea of a countdown to Zero better expressed with the iterate method and easier to understand in terms of walking the array from back to front.
import static java.lang.Math.max;
private static final double EXACT_MATCH = 0d;
public static IntStream reverseStream(final int[] array) {
return countdownFrom(array.length - 1).map(index -> array[index]);
}
public static DoubleStream reverseStream(final double[] array) {
return countdownFrom(array.length - 1).mapToDouble(index -> array[index]);
}
public static <T> Stream<T> reverseStream(final T[] array) {
return countdownFrom(array.length - 1).mapToObj(index -> array[index]);
}
public static IntStream countdownFrom(final int top) {
return IntStream.iterate(top, t -> t - 1).limit(max(0, (long) top + 1));
}
Here are some tests to prove it works:
import static java.lang.Integer.MAX_VALUE;
import static org.junit.Assert.*;
#Test
public void testReverseStream_emptyArrayCreatesEmptyStream() {
Assert.assertEquals(0, reverseStream(new double[0]).count());
}
#Test
public void testReverseStream_singleElementCreatesSingleElementStream() {
Assert.assertEquals(1, reverseStream(new double[1]).count());
final double[] singleElementArray = new double[] { 123.4 };
assertArrayEquals(singleElementArray, reverseStream(singleElementArray).toArray(), EXACT_MATCH);
}
#Test
public void testReverseStream_multipleElementsAreStreamedInReversedOrder() {
final double[] arr = new double[] { 1d, 2d, 3d };
final double[] revArr = new double[] { 3d, 2d, 1d };
Assert.assertEquals(arr.length, reverseStream(arr).count());
Assert.assertArrayEquals(revArr, reverseStream(arr).toArray(), EXACT_MATCH);
}
#Test
public void testCountdownFrom_returnsAllElementsFromTopToZeroInReverseOrder() {
assertArrayEquals(new int[] { 4, 3, 2, 1, 0 }, countdownFrom(4).toArray());
}
#Test
public void testCountdownFrom_countingDownStartingWithZeroOutputsTheNumberZero() {
assertArrayEquals(new int[] { 0 }, countdownFrom(0).toArray());
}
#Test
public void testCountdownFrom_doesNotChokeOnIntegerMaxValue() {
assertEquals(true, countdownFrom(MAX_VALUE).anyMatch(x -> x == MAX_VALUE));
}
#Test
public void testCountdownFrom_givesZeroLengthCountForNegativeValues() {
assertArrayEquals(new int[0], countdownFrom(-1).toArray());
assertArrayEquals(new int[0], countdownFrom(-4).toArray());
}
Based on #stuart-marks's answer, but without casting, function returning stream of list elements starting from end:
public static <T> Stream<T> reversedStream(List<T> tList) {
final int size = tList.size();
return IntStream.range(0, size)
.mapToObj(i -> tList.get(size - 1 - i));
}
// usage
reversedStream(list).forEach(System.out::println);
What's the proper generic way to reverse a stream?
If the stream does not specify an encounter order, don't.
(!s.spliterator().hasCharacteristics(java.util.Spliterator.ORDERED))
The most generic and the easiest way to reverse a list will be :
public static <T> void reverseHelper(List<T> li){
li.stream()
.sorted((x,y)-> -1)
.collect(Collectors.toList())
.forEach(System.out::println);
}
Java 8 way to do this:
List<Integer> list = Arrays.asList(1,2,3,4);
Comparator<Integer> comparator = Integer::compare;
list.stream().sorted(comparator.reversed()).forEach(System.out::println);

Categories