neox2811
neox2811

Reputation: 97

Java Long Stream contains specific number

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

Answers (5)

Malte Hartwig
Malte Hartwig

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

Roland
Roland

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

ZhekaKozlov
ZhekaKozlov

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 found
  • summary.getMin() == 0: at least one non-n is found

Upvotes: 1

wero
wero

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

Andy Turner
Andy Turner

Reputation: 140318

You can reduce the stream, keeping a pair of booleans:

  • The first indicating whether you found at least 1 occurrence of n;
  • The second indicating whether you found at least 1 occurrence of something other than n.

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

Related Questions