我有类似以下内容:

public class MyClass {
private Long stackId
private Long questionId
}

例如100的集合,其中stackid可以使用不同的questionId复制。 stackId和questionId之间的一对多关系

是否存在流式,Java 8转换为以下结构的方式:
public class MyOtherClass {
private Long stackId
private Collection<Long> questionIds
}

这将是25个的集合,每个实例具有4个QuestionId的嵌套集合。

输入:
[{1,100},{1,101},{1,102},{1,103},{2,200},{2,201},{2,202},{1,203}]

输出量
[{1, [100,101,102,103]},{2,[200,201,202,203]}]

最佳答案

Stream API的直接方法涉及2条Stream管道:

  • 第一个将Map<Long, List<Long>>的临时stackId创建为questionIds。这是通过 groupingBy(classifier, downstream) 收集器完成的,其中我们根据stackId进行分类,并将具有相同stackId的值映射到其questionId(使用 mapping ),并使用 toList() 收集到列表中。
  • 第二个将该映射的每个条目转换为MyOtherClass实例,并将其收集到列表中。

  • 假设您有一个构造函数MyOtherClass(Long stackId, Collection<Long> questionIds),则示例代码为:
    Map<Long, List<Long>> map =
        list.stream()
            .collect(Collectors.groupingBy(
                MyClass::getStackId,
                Collectors.mapping(MyClass::getQuestionId, Collectors.toList())
            ));
    
    List<MyOtherClass> result =
        map.entrySet()
           .stream()
           .map(e -> new MyOtherClass(e.getKey(), e.getValue()))
           .collect(Collectors.toList());
    

    使用StreamEx库,您可以在单个Stream管道中完成此操作。该库提供了 pairing first 收集器。这样可以配对两个收集器,并对两个收集的结果执行整理器操作:
  • 第一个仅保留分组元素的第一个stackId(根据构造,它们将完全相同)
  • 第二个将每个元素映射到其questionId并收集到列表中。
  • 整理程序操作仅返回MyOtherClass的新实例。

  • 样例代码:
    import static java.util.stream.Collectors.collectingAndThen;
    import static java.util.stream.Collectors.mapping;
    import static java.util.stream.Collectors.toList;
    import static one.util.streamex.MoreCollectors.first;
    import static one.util.streamex.MoreCollectors.pairing;
    
    // ...
    
    Collection<MyOtherClass> result =
        StreamEx.of(list)
                .groupingBy(
                    MyClass::getStackId,
                    pairing(
                        collectingAndThen(mapping(MyClass::getStackId, first()), Optional::get),
                        mapping(MyClass::getQuestionId, toList()),
                        MyOtherClass::new
                    )
                ).values();
    

    07-24 18:21