首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >分裂java.util.stream.Stream

分裂java.util.stream.Stream
EN

Stack Overflow用户
提问于 2015-05-13 10:56:22
回答 4查看 1.3K关注 0票数 13

我有一个文本文件,其中包含URL和电子邮件。我需要从文件中全部提取出来。每个URL和电子邮件可以找到不止一次,但结果不应包含重复。我可以使用以下代码提取所有URL:

代码语言:javascript
运行
复制
Files.lines(filePath).
    .map(urlPattern::matcher)
    .filter(Matcher::find)
    .map(Matcher::group)
    .distinct();

我可以使用以下代码提取所有电子邮件:

代码语言:javascript
运行
复制
Files.lines(filePath).
    .map(emailPattern::matcher)
    .filter(Matcher::find)
    .map(Matcher::group)
    .distinct();

我能否只提取一次读取Files.lines(filePath)返回的流的所有URL和电子邮件?就像分割行流、URL流和电子邮件流一样。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-05-13 11:05:14

您可以使用partitioningBy收集器,尽管它仍然不是非常优雅的解决方案。

代码语言:javascript
运行
复制
Map<Boolean, List<String>> map = Files.lines(filePath)
        .filter(str -> urlPattern.matcher(str).matches() ||
                       emailPattern.matcher(str).matches())
        .distinct()
        .collect(Collectors.partitioningBy(str -> urlPattern.matcher(str).matches()));
List<String> urls = map.get(true);
List<String> emails = map.get(false);

如果不想两次应用regexp,可以使用中间对对象(例如,SimpleEntry):

代码语言:javascript
运行
复制
public static String classify(String str) {
    return urlPattern.matcher(str).matches() ? "url" : 
        emailPattern.matcher(str).matches() ? "email" : null;
}

Map<String, Set<String>> map = Files.lines(filePath)
        .map(str -> new AbstractMap.SimpleEntry<>(classify(str), str))
        .filter(e -> e.getKey() != null)
        .collect(Collectors.groupingBy(e -> e.getKey(),
            Collectors.mapping(e -> e.getValue(), Collectors.toSet())));

使用我的免费StreamEx库,最后一步将更短:

代码语言:javascript
运行
复制
Map<String, Set<String>> map = StreamEx.of(Files.lines(filePath))
        .mapToEntry(str -> classify(str), Function.identity())
        .nonNullKeys()
        .grouping(Collectors.toSet());
票数 10
EN

Stack Overflow用户

发布于 2015-05-13 11:26:39

您可以在Collector中执行匹配。

代码语言:javascript
运行
复制
Map<String,Set<String>> map=Files.lines(filePath)
    .collect(HashMap::new,
        (hm,line)-> {
            Matcher m=emailPattern.matcher(line);
            if(m.matches())
              hm.computeIfAbsent("mail", x->new HashSet<>()).add(line);
            else if(m.usePattern(urlPattern).matches())
              hm.computeIfAbsent("url", x->new HashSet<>()).add(line);
        },
        (m1,m2)-> m2.forEach((k,v)->m1.merge(k, v,
                                     (s1,s2)->{s1.addAll(s2); return s1;}))
    );
Set<String> mail=map.get("mail"), url=map.get("url");

请注意,这可以很容易地调整为在一行中找到多个匹配:

代码语言:javascript
运行
复制
Map<String,Set<String>> map=Files.lines(filePath)
    .collect(HashMap::new,
        (hm,line)-> {
            Matcher m=emailPattern.matcher(line);
            while(m.find())
              hm.computeIfAbsent("mail", x->new HashSet<>()).add(m.group());
            m.usePattern(urlPattern).reset();
            while(m.find())
              hm.computeIfAbsent("url", x->new HashSet<>()).add(m.group());
        },
        (m1,m2)-> m2.forEach((k,v)->m1.merge(k, v,
                                     (s1,s2)->{s1.addAll(s2); return s1;}))
    );
票数 4
EN

Stack Overflow用户

发布于 2015-05-13 11:04:15

因为您不能重用Stream,所以我认为唯一的选择是“手动执行”。

代码语言:javascript
运行
复制
File.lines(filePath).forEach(s -> /** match and sort into two lists */ );

如果有另外的解决办法,尽管我会很高兴了解它!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30212801

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档