How to use a thread to do something one on elements not in an index, but another on yes-in-range?

This question

Is there a compressed way to iterate over a stream with indexes in Java 8?

describes how to manage one thread based on another index thread. My goal is to take an array of strings

one two three four five six seven eight 

and all-cap elements with an array index between 2 and 5:

 one two three four five six seven eight 

I figured out how to do this, but my instinct says there should be a more elegant way to get around this. In the example below, the first stream filters all elements except ranges. Of course, this is not what I want, but it is similar to how it uses a stream to filter by index. The second modifies the elements of the array in place using the ones I want.

I don't like how it modifies the array in place and how it needs two threads. 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 
+4
source share
3 answers

I also thought that there should be a map(predicate, functionIfTrue, functionIfFalse) method map(predicate, functionIfTrue, functionIfFalse) , but it is not. Instead, use a three-dimensional map on the map:

 final int[] idx = {-1}; // trick to get around "effectively final" String result = Arrays.stream(input.split(" ")) .map(s -> MIN_IDX <= ++idx[0] && idx[0] <= MAX_IDX ? s.toUpperCase() : s) .collect(joining(" ")); 

This uses the trick to get the iteration index using a single array of elements, which itself is final, but whose contents are modified.


Some test codes:

 final String input = "one two three four five six seven eight"; final int MIN_IDX = 2; final int MAX_IDX = 5; final int[] idx = {-1}; String result = Arrays.stream(input.split(" ")) .map(s -> MIN_IDX <= ++idx[0] && idx[0] <= MAX_IDX ? s.toUpperCase() : s) .collect(joining(" ")); System.out.println(result); 

Output:

 one two THREE FOUR FIVE SIX seven eight 
+1
source

Here is a solution without Stream . Use subList to get an idea of ​​the range you want to use as a List . Then use replaceAll to convert the elements into 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 replaceAll parameter is the exclusive index value.

+3
source

Here's a Stream API based solution that is parallel:

 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(" ")); 

Please note that I am posting this answer for completeness only. Threads are not suitable for indexed operations. I vote for @SotiriosDelimanolis solution, it is really simple and elegant.

+3
source

All Articles