Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 370
neox2811 Avatar asked May 30 '17 07:05

neox2811


2 Answers

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;
like image 96
Malte Hartwig Avatar answered Nov 09 '22 09:11

Malte Hartwig


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;
like image 2
Andy Turner Avatar answered Nov 09 '22 07:11

Andy Turner