Java Lambda thread to different collections

I have a Java lambda stream that parses a file and stores the results in a collection based on some basic filtering.

I just study lambdas, so bear with me if it's ridiculously bad. But please feel free to point out my mistakes.

For this file:

#ignored this is #ignored working fine 

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 am I going to collect ignored lines in a second list in the same thread? Sort of:

 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 understand that it would be rather trivial to open a new stream, change the logic a bit and .collect () ignored lines. But I don’t want to loop through this file twice if I can do all this in one thread.

+5
source share
2 answers

Instead of two threads, 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 the key as a Boolean , but you can change it to a meaningful string or enumeration

EDIT

If lines can start with some other special characters, you can 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

+13
source

I think that the closest you can come to a common approach for this is something like peek :

 g.peek(line -> if (line.startsWith("#")) { ignored.add(line); }) .filter(line -> !line.startsWith("#")) // how can I add a condition to throw these // non-matching lines into the ignored collection? .collect(Collectors.toList()); 

I mention this because, unlike the Collector splitting, you could, at least theoretically, change each other, no matter how many peek you want, but as you can see, you need to duplicate the logic, so it is not perfect.

+1
source

Source: https://habr.com/ru/post/1258116/


All Articles