有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java收集器。减少到列表

考虑这类:

@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
    String name;
    String languages;
}

我有一个List<User>,我想减少对语言的学习。输入:

List<User> list = new ArrayList<>();
list.add(new User("sam", "java"));
list.add(new User("sam", "js"));
list.add(new User("apollo", "html"));

预期产出:

[User(name=apollo, languages=html), User(name=sam, languages=java, js)]

我可以使用以下代码实现这一点:

List<User> l = list.stream()
    .collect(Collectors.groupingBy(
         u -> u.name,
         Collectors.reducing((u1, u2) -> 
             new User(u1.name, u1.languages + ", " + u2.languages))))
    .values()
    .stream()
    .filter(user -> user.get() != null)
    .map(user -> user.get())
    .collect(Collectors.toList());

System.out.println(l);

但我不想创建两个流,可以使用单个流实现吗


共 (2) 个答案

  1. # 1 楼答案

    But I don't want to create two stream, can this be achieved using a single stream?

    当然,这是可能的,您有两个选项,并且在这两个选项中都必须使用Collect.collectingAndThen从创建的Map中提取正确的值类型

    首先需要使用以下lambda表达式:

    BinaryOperator<User> binaryOperator = (u1, u2) -> 
        new User(u1.getName(), String.join(", ", u1.getLanguages(), u2.getLanguages()));
    

    解决方案:

    1. Collectors.toMap使用Collectors.collectingAndThenMap<String, User>中提取值:

      List<User> l = list.stream()                                       // Stream<User>
          .collect(Collectors.collectingAndThen(
              Collectors.toMap(                                          // Map
                  User::getName,                                         // ..name as key
                  user -> new User(user.getName(), user.getLanguages()), // ..value as user
                  binaryOperator),                                       // ..combined
              map -> new ArrayList<>(map.values())));                    // extracted value
      
    2. Collectors.groupingBy通过Collectors.collectingAndThenMap<String, Optional<User>>中提取由Collectors.reducing引起的值:

      List<User> ll = list.stream()                     // Stream<User>
          .collect(Collectors.collectingAndThen(
              Collectors.groupingBy(                    // Map<String, Optional<User>>
                  User::getName,                        // ... name as key
                  Collectors.reducing(binaryOperator)), // ... reduced value
              map -> map.values().stream()              // extracted value
                  .filter(Optional::isPresent)          // ... where is Optional present
                  .map(Optional::get)                   // ... get it
                  .collect(Collectors.toList())));      // ... create a List<User>
      

    注意:我假设您使用,那么可能会有另一个使用或更高版本的解决方案

  2. # 2 楼答案

    你可以使用Collectors.toMap()

    List<User> l = new ArrayList<> (list.stream()
        .collect(Collectors.toMap(u -> u.name,
                                  u -> new User (u.name,u.languages),
                                  (u1, u2) -> new User(u1.name, u1.languages + ", " + u2.languages)))
        .values());