当前位置: 首页 > 知识库问答 >
问题:

如何合并基于重复的父对象列表中的子对象

施喜
2023-03-14

我有两个具有一对多关系的实体,它们通过复合主键连接在一起。由于Spring Data为oracle数据库生成错误计数不同的查询,我SQL笛卡尔连接的输出,这导致每一行子对象都重复父对象的行。我需要找出基于复合键的不同的父对象,然后在列表中为父对象添加每个子对象,并将其设置为父对象的属性

我能够根据父对象的组合键找到不同的父对象。以下是相关代码

private static <T> Predicate<T> distinctByKeys(Function<? super T, ?>... keyExtractors)
{
final Map<List<?>, Boolean> seen = new ConcurrentHashMap<>();
return t ->
{
final List<?> keys = Arrays.stream(keyExtractors)
.map(ke -> ke.apply(t))
collect(Collectors.toList());

return seen.putIfAbsent(keys, Boolean.TRUE) == null;
};
}

假设我有以下输入

list.add(new Book("Core Java", 200, new ArrayList(){{add("Page 1");}}));
list.add(new Book("Core Java", 200, new ArrayList(){{add("Page 2");}}));
list.add(new Book("Learning Freemarker", 150, new ArrayList(){{add("Page 15");}}));
list.add(new Book("Spring MVC", 300, new ArrayList(){{add("Page 16");}}));
list.add(new Book("Spring MVC", 300, new ArrayList(){{add("Page 17");}}));

我需要产生以下输出

Core Java,200, [Page 1, Page 2]
Learning Freemarker,150, [Page 15]
Spring MVC,300 , [Page 16, Page 17]

这方面的任何帮助都会很有帮助

共有1个答案

楚元章
2023-03-14

一个选项是使用收集器。toMap()使用标题页面值作为键。如果发现重复项,则可以合并两个列表:

Collection<Book> result = list.stream()
        .collect(Collectors.toMap(
                b -> Map.entry(b.getTitle(), b.getPages()),
                b -> new Book(b.getTitle(), b.getPages(), b.getList()),
                (b1, b2) -> new Book(b1.getTitle(), b1.getPages(),
                        Stream.concat(b1.getList().stream(), b2.getList().stream()).collect(Collectors.toList())),
                LinkedHashMap::new))
        .values();

或者,您可以使用收集器。groupingBy()

List<Book> result = list.stream().collect(
        Collectors.groupingBy(b -> Map.entry(b.getTitle(), b.getPages()), LinkedHashMap::new,
                Collectors.flatMapping(b -> b.getList().stream(), Collectors.toList())))
        .entrySet().stream()
        .map(e -> new Book(e.getKey().getKey(), e.getKey().getValue(), e.getValue()))
        .collect(Collectors.toList());

第二种方法使用titlepage作为键创建一个Map,并使用Collectors.flat映射()合并所有书籍的列表。之后,您将条目映射回Book对象。

如果无法使用采集器。flatMapping()使用收集器。mapping()`相反:

List<Book> r = list.stream().collect(
        Collectors.groupingBy(b -> Map.entry(b.getTitle(), b.getPages()), LinkedHashMap::new,
                Collectors.mapping(Book::getList, Collectors.toList())))
        .entrySet().stream()
        .map(e -> new Book(e.getKey().getKey(), e.getKey().getValue(), 
                e.getValue().stream().flatMap(Collection::stream).collect(Collectors.toList())))
        .collect(Collectors.toList());

如果不能使用Map.entry(),请使用new AbstractMap。简单入口

这两种情况的结果都是:

Book[title='Core Java', pages=200, list=[Page 1, Page 2]]
Book[title='Learning Freemarker', pages=150, list=[Page 15]]
Book[title='Spring MVC', pages=300, list=[Page 16, Page 17]]

 类似资料:
  • 我有以下Java POJO 如何实现在游戏对象列表中确定重复字段的功能? 例如,当两个游戏有相同的开始日期? 我以前使用过,但仅在根据最早日期等对对象进行排序时使用过,但它能否用于对重复项进行排序?

  • 父类: 子电话对象(第一级): 我正在尝试获取person对象,其phone对象类型为home,其编号应包含“888”。 从上面的流代码,我能够得到手机对象。但是如何在相同的函数中获得该电话对象的父对象呢?。 我尝试了这种方式,我得到null不匹配的对象。

  • 我需要筛选我的对象列表: 以便将具有相同和的所有对象合并到具有以下属性的单个对象中: 作为所有值的和 作为所有值的字符串级联 所以结果是: Java 8中的溪流有可能做到吗? 我尝试了几种方法(例如,还使用),但我没有找到解决方案! 谢谢 编辑: 下面是我尝试的: 但由于某种原因,在计算过程中,我在上得到了,无论如何,我非常肯定这不是一个有效的解决方案。

  • 假设我们有: 我们有一个实例列表,即

  • 请建议更好的方法将路线转换为路线地图。

  • 当我对它进行降序排序时,它应该首先显示Parent3,因为它有一个Z。这是我当前的hql,它得到了1>2>3的错误结果: 如果没有distinct,尽管它选择了多个相同的父级,但它仍然很好。 我有一个模型设置如下: 编辑:在集合中按HQL顺序对其进行排序,尽管当双亲具有相同的children.name值时,它不会比较下一个可能的值。即。 如果Parent1有孩子abba,zeon Parent2有