This question
Is there a concise way to iterate over a stream with indices in Java 8?
describes how to drive one stream based on another stream of indexes. My goal is to take an array of strings
one two three four five six seven eight
and all-cap the elements having an array index between 2 and 5:
one two THREE FOUR FIVE SIX seven eight
I've figured out how to do this, but my instinct says there should be a more elegant way of going about it. In the below example, the first stream filters out all elements except those in range. It's not directly what I want, of course, but it's similar in how it uses a stream to filter by index-range. The second alters the array elements in place, capitalizing the ones I want.
I don't like how it alters the array in place, and how it requires two streams. Is there a better way?
import static java.util.stream.Collectors.joining;
import java.util.Arrays;
import java.util.stream.IntStream;
public class UpperCaseElementsInIndexRangeViaIntStream {
public static void main(String[] ignored) {
final String input = "one two three four five six seven eight";
final int MIN_IDX = 2;
final int MAX_IDX = 5;
final String[] splits = input.split(" ");
//Filter only those in range
String output = IntStream.range(0, splits.length).
filter(idx -> MIN_IDX <= idx && idx <= MAX_IDX).
mapToObj(i -> splits[i]).
collect(joining(" "));
System.out.println(output);
//Change the array in place, capitalizing only those in range
IntStream.range(0, splits.length).forEach(idx -> {
final String split = splits[idx];
splits[idx] = (MIN_IDX <= idx && idx <= MAX_IDX)
? split.toUpperCase() : split;
});
output = Arrays.stream(splits).collect(joining(" "));
System.out.println(output);
}
}
Output:
three four five six
one two THREE FOUR FIVE SIX seven eight
Here's a solution without Stream
. Use subList
to get a view of the range you want as a List
. Then use replaceAll
to transform the elements in place.
List<String> all = Arrays.asList(splits);
all.subList(MIN_IDX, MAX_IDX + 1).replaceAll(String::toUpperCase);
// use 'all' as needed
Note that the second parameter of replaceAll
is an exclusive index value.
Here's the Stream API-based solution which is parallel friendly:
final String[] splits = input.split(" ");
String output = IntStream.range(0, splits.length).parallel()
.mapToObj(idx -> MIN_IDX <= idx && idx <= MAX_IDX ?
splits[idx].toUpperCase() : splits[idx])
.collect(Collectors.joining(" "));
Note that I'm posting this answer just for the completeness. Streams are not well-suitable for indexed operations. I vote for @SotiriosDelimanolis solution, it's really simple and elegant.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With