I think this is a great case to not use streams. Stream are not always the best approach when stateful operations are involved.
But it can be definitely done, and also the question asks specifically for streams, so you can use the followings.
Using forEachOrdered
You can use forEachOrdered
with should ensure the order (here obvioulsy the stream has to be sequential):
public static int[] deleteNth(int[] elements, int maxOcurrs) {
List<Integer> list = new ArrayList<>();
Arrays.stream(elements).forEachOrdered(elem -> {
if (Collections.frequency(list, elem) < maxOcurrs) list.add(elem);
});
return list.stream().mapToInt(Integer::intValue).toArray();
}
Using collect
Given some circunstanses you can use the collect
method to accomplish this.
When the stream is ordered and sequential, which is the case of Arrays.stream(elements).boxed()
, the collect()
method does not use the combiner operator (this is truth for java8 and java9 current realease, and however is not guaranteed to work exactly the same in next releases, because many optimizations can occur).
This implementation keeps the order of the stream, and as mentioned before works fine in the current releases. Like the answer in the link below says, and also in my personal opinion, i find very difficult that the implementation of collect
in sequential streams will ever need to use the combiner.
The code of the collect method is the following:
public static int[] deleteNth(int[] elements, int maxOcurrs) {
return Arrays.stream(elements).boxed()
.collect(() -> new ArrayList<Integer>(),
(list, elem) -> {
if (Collections.frequency(list, elem) < maxOcurrs) list.add(elem);
},
(list1, list2) -> {
throw new UnsupportedOperationException("Undefined combiner");
})
.stream()
.mapToInt(Integer::intValue)
.toArray();
}
This collector
creates an ArrayList
, and when is goind to add the new element checks if the maxOcurrences
is met, if is not, then adds the element. Like mentioned before, and in the answer below, the combiner is not called at all. This persforms a little better than n^2
.
More information of why the combiner method is not called in sequentials streams can be found here.