I have a Java lambda stream that parses a file and stores the results into a collection, based on some basic filtering.
I'm just learning lambdas so bear with me here if this is ridiculously bad. But please feel free to point out my mistakes.
For a given file:
#ignored
this
is
#ignored
working
fine
The code:
List<String> matches;
Stream<String> g = Files.lines(Paths.get(givenFile));
matches = g.filter(line -> !line.startsWith("#"))
.collect(Collectors.toList());
["this", "is", "working", "fine"]
Now, how would I go about collecting the ignored lines into a second list within this same stream? Something like:
List<String> matches;
List<String> ignored; // to store lines that start with #
Stream<String> g = Files.lines(Paths.get(exclusionFile.toURI()));
matches = g.filter(line -> !line.startsWith("#"))
// how can I add a condition to throw these
// non-matching lines into the ignored collection?
.collect(Collectors.toList());
I realize it would be pretty trivial to open a new stream, alter the logic a bit, and .collect() the ignored lines easily enough. But I don't want to have to loop through this file twice if I can do it all in one stream.
Differences between a Stream and a Collection: A stream does not store data. An operation on a stream does not modify its source, but simply produces a result. Collections have a finite size, but streams do not.
The toMap collector can be used to collect Stream elements into a Map instance.
Difference Between Collections Vs Streams In Java :Collections are mainly used to store and group the data. Streams are mainly used to perform operations on data. You can add or remove elements from collections. You can't add or remove elements from streams.
You obtain a stream from a collection by calling the stream() method of the given collection. Here is an example of obtaining a stream from a collection: List<String> items = new ArrayList<String>(); items. add("one"); items.
Instead of two streams you can use partitioningBy
in Collector
List<String> strings = Arrays.asList("#ignored", "this", "is", "#ignored", "working", "fine");
Map<Boolean, List<String>> map = strings.stream().collect(Collectors.partitioningBy(s -> s.startsWith("#")));
System.out.println(map);
output
{false=[this, is, working, fine], true=[#ignored, #ignored]}
here I used key as Boolean
but you can change it to a meaningful string or enum
EDIT
If the strings can starts with some other special characters you could use groupingBy
List<String> strings = Arrays.asList("#ignored", "this", "is", "#ignored", "working", "fine", "!Someother", "*star");
Function<String, String> classifier = s -> {
if (s.matches("^[!@#$%^&*]{1}.*")) {
return Character.toString(s.charAt(0));
} else {
return "others";
}
};
Map<String, List<String>> maps = strings.stream().collect(Collectors.groupingBy(classifier));
System.out.println(maps);
Output
{!=[!Someother], #=[#ignored, #ignored], *=[*star], others=[this, is, working, fine]}
also you can nest groupingBy
and partitioningBy
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