Is there a way to achieve this using Java Streams?
List<String> list = new ArrayList<>();
list.add("x=aa,y=bb,y=cc");
list.add("y=dd,z=ee,w=ff");
list.add("w=gg,w=hh,w=ii");
and I want to filter above ArrayList to contain only string values of type 'y'. Like below
list=["bb","cc","dd"]
I am able to achieve this using multiple lines of code using String.split(",") and inserting eligible substring to a new ArrayList. But is there a clean way to achieve this using Java Streams?
CodePudding user response:
You asked:
is there a clean way to achieve this using Java Streams?
Yes. Indeed, you can process your inputs, filter out the unwanted parts, and produce a finished list, all using streams.
First define some example data, a list of inputs.
Generate a stream from that list. This stream has 3 elements, given our example data.
Call Stream#flatMap
to return a new stream whose elements are made from pieces of the original stream’s elements. The new stream has 9 elements, produced by breaking each of the 3 original elements into 3 parts each (3 * 3 = 9).
Filter the newer longer stream for elements whose text starts with our targeted y=
prefix.
Transform each of the string elements that passed our filter’s predicate test. Use simple string manipulation to replace "y=" with an empty string. So a value such as y=bb
becomes bb
.
Collect transformed strings by gathering into a new List
object.
List < String > inputs =
List.of(
"x=aa,y=bb,y=cc" ,
"y=dd,z=ee,w=ff" ,
"w=gg,w=hh,w=ii"
);
List < String > results =
inputs
.stream() // Generate stream whose elements are each of the list’s elements.
.flatMap( input -> Arrays.stream( input.split( "," ) ) ) // Break each element into parts, feeding each part into a new longer stream.
.filter( pairing -> pairing.startsWith( "y=" ) ) // Filter out any strings not beginning with `y=`.
.map( pairing -> pairing.replace( "y=" , "" ) ) // A value such as `y=bb` becomes `bb`.
.toList(); // Collect transformed strings into a new list.
When run.
results.toString() = [bb, cc, dd]
To put results in sorted order, add a call to .sorted()
before the toList()
.
CodePudding user response:
Here is one way.
List<String> list = new ArrayList<>();
list.add("x=aa,y=bb,y=cc");
list.add("y=dd,z=ee,w=ff");
list.add("w=gg,w=hh,w=ii");
List<String> result = getListOf(list,"y");
System.out.println(result);
prints
[bb, cc, dd]
- stream the strings and split on
","
- then split those on
"="
which returns arrays likearr = [x,aa]
- then filter on
arr[0]
and returnarr[1]
if it matches. - and return the resultant list.
public static List<String> getListOf(List<String> items, String key) {
return items.stream()
.flatMap(str -> Arrays.stream(str.split(",")))
.map(str -> str.split("="))
.filter(s -> s[0].equals(key))
.map(s -> s[1])
.toList();
}
You can avoid flatMapping by using mapMulti
(Java 16) Note: stole idea of startsWith
from Basil Bourque's answer.
public static List<String> getListOf(List<String> items, String key) {
final String kk = key "=";
return items.stream().<String>mapMulti((str,putOnStream)-> {
for (String s : str.split(",")) {
if (s.startsWith(kk)) {
putOnStream.accept(s.substring(kk.length()));
}
}})
.toList();
}