likejudo
likejudo

Reputation: 3735

Where does `return;` in Stream.forEach() break control to?

Where does return; in Stream.forEach() break control to?

I expected after this statement was printed, that the forEach would be exited and into the rest of the method.

returning nMissing: 2

But instead, I find that instead it goes back to process the rest of the stream.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class MissingKInteger {
    int currentItem = 0;
    int nMissing = 0;
    ArrayList<Integer> al = new ArrayList<Integer>();

    public int findKthPositive(int[] arr, int k) {
        Arrays.stream(arr).forEach(x -> {
            System.out.format("--- examine x %d ---\n", x);
            if (x - currentItem == 1) {
                currentItem++;
                System.out.format("step. currentItem %d, nMissing %d\n", currentItem, nMissing);
            } else {
                do {
                    nMissing++;
                    currentItem++;
                    al.add(currentItem);
                    System.out.format("loop. currentItem %d, nMissing %d\n", currentItem, nMissing);
                    if(nMissing == k) {
                        System.out.format("returning nMissing: %d" , nMissing);
                        return;             
                    }
                } while (x - currentItem > 1);
                currentItem = x;
            }
            System.out.format("out of loop. currentItem %d, nMissing %d\n", currentItem, nMissing);

        });
        if(nMissing < k) {
            currentItem += (k - nMissing);
            return currentItem;
        }
        System.out.println();
        System.out.println("al:" + al);
        return currentItem;
    }

    public static void main(String[] args) {
        MissingKInteger missingKInteger = new MissingKInteger();
        // [1,3] k=1 ans = 2
        // [ 2,3,4,7,11 ] k=5 ans = 9
        // { 2,3,4,7,11 } k= ans = 
        
        int[] arr = new int[] { 3,10 };
        int k = 2;
        System.out.println("input arr is:" + Arrays.toString(arr));
        System.out.println("find " + k + "-th integer");

        int ans = missingKInteger.findKthPositive(arr, k);
        System.out.println(k + "-th integer:" + ans);
    }

Output is:

input arr is:[3, 10]
        find 2-th integer
        --- examine x 3 ---
        loop. currentItem 1, nMissing 1
        loop. currentItem 2, nMissing 2
        returning nMissing: 2--- examine x 10 ---
        loop. currentItem 3, nMissing 3
        loop. currentItem 4, nMissing 4
        loop. currentItem 5, nMissing 5
        loop. currentItem 6, nMissing 6
        loop. currentItem 7, nMissing 7
        loop. currentItem 8, nMissing 8
        loop. currentItem 9, nMissing 9
        out of loop. currentItem 10, nMissing 9

        al:[1, 2, 3, 4, 5, 6, 7, 8, 9]
        2-th integer:10

background:

I am trying to solve this problem of the k-th missing integer using Java 8 Streams.

Given an array arr of positive integers sorted in a strictly increasing order, and an integer k.

Find the kth positive integer that is missing from this array.

Example 1:

Input: arr = [2,3,4,7,11], k = 5 Output: 9 Explanation: The missing positive integers are [1,5,6,8,9,10,12,13,...]. The 5th missing positive integer is 9.

Example 2:

Input: arr = [1,2,3,4], k = 2 Output: 6 Explanation: The missing positive integers are [5,6,7,...]. The 2nd missing positive integer is 6.

of course, an iterative solution would be

class Solution {

    public int findKthPositive(int[] arr, int k) {
        int currentItem = 0;
        int nMissing = 0;

        for(int x : arr) {
            if (x - currentItem == 1) { // if it is the next consecutive number e.g. 2,3,4,5... then is is not a candidate
                currentItem++;
            } else { // there is a gap here. get all the numbers in the gap
                endLoop: do {
                    nMissing++; // increment count of missing numbers
                    currentItem++; // yes, this is a missing number
                    if(nMissing == k) { // found the nth missing, stop here
                        return currentItem;             
                    }
                } while (x - currentItem > 1); // while there is a gap
                currentItem = x;
            }
        };
        if(nMissing < k) { // if input array atopped short, then generate remaining missing numbers.
            currentItem += (k - nMissing);
        }
        return currentItem;
    }
}

Upvotes: 0

Views: 126

Answers (1)

Oliver
Oliver

Reputation: 503

Because return in Stream.forEach or Iterable.forEach is effectively synonymous to continue in traditional for loops or for each loops. Remember that the method (whether anonymous or not) that is your argument, is being called for each element in the stream. return is returning that method, not the method calling your method. For example:

IntStream.range(0, 5).forEach(i -> {
  if(i == 3) return;

  System.out.print(i);
}

Will print:

0124

Upvotes: 5

Related Questions