简体   繁体   English

Java Lambda流进入不同的集合

[英]Java Lambda stream into different collections

I have a Java lambda stream that parses a file and stores the results into a collection, based on some basic filtering. 我有一个Java lambda流,它根据一些基本过滤来解析文件并将结果存储到一个集合中。

I'm just learning lambdas so bear with me here if this is ridiculously bad. 我只是在学习lambdas,所以如果这是非常糟糕的话,请耐心等待我。 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. 我意识到打开一个新的流,稍微改变一下逻辑并且.collect()容易被忽略的行是非常简单的。 But I don't want to have to loop through this file twice if I can do it all in one stream. 但是,如果我可以在一个流中完成所有操作,我不想两次遍历此文件。

Instead of two streams you can use partitioningBy in Collector 您可以在收集器中使用partitioningBy而不是两个流

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 这里我使用key作为Boolean但您可以将其更改为有意义的字符串或枚举

EDIT 编辑

If the strings can starts with some other special characters you could use groupingBy 如果字符串可以从其他一些特殊字符开始,则可以使用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 你也可以嵌套groupingBypartitioningBy

I think the closest you could come to a generic approach for this would be something like peek : 我认为最接近你可以采用通用的方法就像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 it because unlike with the partitioning Collector you could, at least in theory, change together however many peek s you want--but, as you can see, you have to duplicate logic, so it's not ideal. 我提到它,因为不像分区Collector ,你可以,至少在理论上,一起然而,许多改变peek是你想要的-但是,正如你所看到的,你要复制的逻辑,所以它的效果并不理想。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM