Reputation: 97
I want to check, if a LongStream
contains a specific number at least once, but not totally consists of this number:
My approach:
public static boolean containsNum(LongStream input, int n) {
return input.anyMatch(i -> i == n);
}
Tests:
assertEquals(false, containsNum(LongStream.of(1, 2, 3), 19)); // ok
assertEquals(true, containsNum(LongStream.of(1, 2, 3, 19), 19)); //ok
assertEquals(true, containsNum(LongStream.of(1, 19, 19), 19)); //ok
assertEquals(false, containsNum(LongStream.of(1), 19)); //ok
assertEquals(false, containsNum(LongStream.of(19, 19), 19)); // FAIL
assertEquals(false, containsNum(LongStream.of(19), 19)); //FAIL
I know that anyMatch
can´t work in my problem, but the best solution I found. How can I get all tests passing?
Upvotes: 5
Views: 848
Reputation: 4555
It sounds like a reduce function, as Andy's answer shows, but that would go through the whole stream instead of stopping as soon as you found the number and a different number.
The problem is that those ...Match
methods of streams only look at one element at a time, i.e. you would have to save knowledge about the passed elements in some outside state variable. wero and Roland demonstrate this in their answers.
One possibility without relying on outside state while only checking as many elements as necessary would be:
boolean pass = longStream.map(l -> l == number ? 1 : 0)
.distinct()
.limit(2)
.count()
== 2;
Upvotes: 11
Reputation: 7853
Based on wero's answer:
public static boolean containsNum(LongStream input, int n) {
final AtomicBoolean different = new AtomicBoolean();
final AtomicBoolean equals = new AtomicBoolean();
return input.anyMatch(i -> {
different.compareAndSet(false, i != n);
equals.compareAndSet(false, i == n);
return different.get() && equals.get();
});
}
Upvotes: 0
Reputation: 39536
xD:
public static boolean containsNum(LongStream input, int n) {
LongSummaryStatistics summary = input.map(i -> i == n ? 1 : 0).summaryStatistics();
return summary.getMax() == 1 && summary.getMin() == 0;
}
Explanation:
summary.getMax() == 1
: at least one n is foundsummary.getMin() == 0
: at least one non-n is foundUpvotes: 1
Reputation: 32980
Keep track if you have seen n
and non n
:
public static boolean containsNum(LongStream input, int n) {
boolean[] seen = new boolean[2];
return input.anyMatch(i -> { seen[i==n ? 0 : 1] = true; return seen[0] && seen[1]; });
}
Upvotes: -2
Reputation: 140318
You can reduce the stream, keeping a pair of booleans:
Let's say you've got some Pair
class; then:
Stream<Pair> pairs =
input.map(i -> (i == n) ? Pair.of(true, false) : Pair.of(false, true));
Then, reduce this stream by or-ing together the two elements:
Pair reduces =
pairs.reduce(
Pair.of(false, false),
(a, b) -> Pair.of(a.first || b.first, a.second || b.second));
Then check (and return) that both elements are true:
return reduced.first && reduced.second;
Upvotes: 2