我try 做的一个简单示例:

假设我有一个字符串列表,如果包含或不包含特定的子字符串,则需要根据条件将其分为4组.如果一个字符串包含Foo,它应该属于组FOO,如果它包含Bar,它应该属于组BAR,如果它包含两个,它应该出现在两个组中.

List<String> strings = List.of("Foo", "FooBar", "FooBarBaz", "XXX");

由于字符串被分组到第一个匹配组中,因此上述输入的简单方法无法按预期工作:

Map<String,List<String>> result1 =
strings.stream()
        .collect(Collectors.groupingBy(
                        str -> str.contains("Foo") ? "FOO" :
                                    str.contains("Bar") ? "BAR" :
                                            str.contains("Baz") ? "BAZ" : "DEFAULT"));

结果1为

{FOO=[Foo, FooBar, FooBarBaz], DEFAULT=[XXX]}

其中,预期结果应为

{FOO=[Foo, FooBar, FooBarBaz], BAR=[FooBar, FooBarBaz], BAZ=[FooBarBaz], DEFAULT=[XXX]}

在搜索了一段时间后,我找到了另一种方法,接近我想要的结果,但并不完全

Map<String,List<String>> result2 =
List.of("Foo", "Bar", "Baz", "Default").stream()
        .flatMap(str -> strings.stream().filter(s -> s.contains(str)).map(s -> new String[]{str.toUpperCase(), s}))
        .collect(Collectors.groupingBy(arr -> arr[0], Collectors.mapping(arr -> arr[1], Collectors.toList())));

System.out.println(result2);

结果2为

{BAR=[FooBar, FooBarBaz], FOO=[Foo, FooBar, FooBarBaz], BAZ=[FooBarBaz]}

虽然这样可以将包含子字符串的字符串正确地分组到所需的组中,但忽略不包含子字符串的字符串,因此应该属于默认组.预期结果如上所述(顺序无关紧要)

{BAR=[FooBar, FooBarBaz], FOO=[Foo, FooBar, FooBarBaz], BAZ=[FooBarBaz], DEFAULT=[XXX]}

目前,我正在使用两个结果图,并做额外的工作:

result2.put("DEFAULT", result1.get("DEFAULT"));

以上可以一步完成吗?有没有比我上面提到的更好的方法?

推荐答案

这是使用mapMulti的理想 Select .MapMulti采用valueconsumer中的BiConsumer.

这可以通过像之前一样构建Tokenthe containing String的字符串数组并收集(也像之前一样)来实现.如果在字符串中找到了键,则接受包含该键的字符串数组和包含该键的字符串.否则,接受具有默认键和字符串的字符串array.

List<String> strings =
        List.of("Foo", "FooBar", "FooBarBaz", "XXX", "YYY");
Map<String, List<String>> result = strings.stream()
        .<String[]>mapMulti((str, consumer) -> {

            boolean found = false;
            String temp = str.toUpperCase();
            for (String token : List.of("FOO", "BAR",
                    "BAZ")) {
                if (temp.contains(token)) {
                    consumer.accept(
                            new String[] { token, str });
                    found = true;
                }
            }
            if (!found) {
                consumer.accept(
                        new String[] { "DEFAULT", str });
            }
        })
        .collect(Collectors.groupingBy(arr -> arr[0],
                Collectors.mapping(arr -> arr[1],
                        Collectors.toList())));

result.entrySet().forEach(System.out::println);

打印

BAR=[FooBar, FooBarBaz]
FOO=[Foo, FooBar, FooBarBaz]
BAZ=[FooBarBaz]
DEFAULT=[XXX, YYY]

请记住,流是为了让您的编码世界更容易.但有时,只需要使用一些Java 8 struct 的常规循环.除了学术练习外,我可能会这样做.

Map<String,List<String>> result2 = new HashMap<>();

for (String str : strings) {
     boolean added = false;
     String temp = str.toUpperCase();
     for (String token : List.of("FOO","BAR","BAZ")) {
         if(temp.contains(token)) {
             result2.computeIfAbsent(token, v->new ArrayList<>()).add(str);
             added = true;
         }
     }
     if (!added) {
         result2.computeIfAbsent("DEFAULT", v-> new ArrayList<>()).add(str);
     }
}

Java相关问答推荐

将@ManyToOne JPA Composite Key用作Id保存实体添加额外参数

计算战舰沉船/船只的问题(Java)

转换为Biggram

Listview—在Android Java中正确链接项目时出错

了解Android Studio中的调试器输出

Quarkus keycloat配置不工作.quarkus. keycloak. policy—enforcer. enable = true在. yaml表示中不工作

如何以干净的方式访问深度嵌套的对象S属性?

Java FX中的河内之塔游戏-在游戏完全解决之前什么都不会显示

DTO到实体,反之亦然,控制器和服务之间的哪一层应该处理转换?

与Spring Boot相关的实体未正确保存

如何解释Java中for-each循环中对Iterable的强制转换方法引用?

如何从Keyloak映射Hibernate实体中的用户

对字符串长度进行排序,但颠倒了顺序(最长字符串在前)

为什么StandardOpenOption.CREATE不能通过Ubuntu在中小企业上运行?

具有多个模式的DateTimeForMatter的LocalDate.parse失败

在缺少字段时使用Jackson With Options生成Optional.Empty()

根据应用程序 Select 的语言检索数据

Bash数组的单引号元素并使用空格连接

设置背景时缺少Android编辑文本下划线

原始和参数化之间的差异调用orElseGet时可选(供应商)