使用Java流合并列表中相同对象下的列表
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了使用Java流合并列表中相同对象下的列表,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3802字,纯文字阅读大概需要6分钟。
内容图文
我有两个对象如下:
public class A {
private Integer id;
private String name;
private List<B> list;
public A(Integer id, String name, List<B> list) {
this.id = id;
this.name = name;
this.list = list;
}
//getters and setters
}
和
public class B {
private Integer id;
private String name;
public B(Integer id, String name) {
this.id = id;
this.name = name;
}
//getters and setters
}
因此,A包含B的列表,并且有一个填充的A列表如下:
List<A> list = new ArrayList<>();
list.add(new A(1, "a_one", Arrays.asList(new B(1, "b_one"), new B(2, "b_two"))));
list.add(new A(2, "a_two", Arrays.asList(new B(2, "b_two"))));
list.add(new A(1, "a_one", Arrays.asList(new B(3, "b_three"))));
list.add(new A(2, "a_two", Arrays.asList(new B(4, "b_four"), new B(5, "b_five"))));
list.add(new A(3, "a_three", Arrays.asList(new B(4, "b_four"), new B(5, "b_five"))));
我想通过合并具有相同ID的对象来获取新列表.结果列表必须是这样的:
[
A(1, a_one, [B(1, b_one), B(2, b_two), B(3, b_three)]),
A(2, a_two, [B(2, b_two), B(4, b_four), B(5, b_five)]),
A(3, a_three, [B(4, b_four), B(5, b_five)])
]
我确实设法将列表与以下代码合并:
List<A> resultList = new ArrayList<>();
list.forEach(a -> {
if (resultList.stream().noneMatch(ai -> ai.getId().equals(a.getId()))) {
a.setList(list.stream().filter(ai -> ai.getId().equals(a.getId()))
.flatMap(ai -> ai.getList().stream()).collect(Collectors.toList()));
resultList.add(a);
}
});
我的问题是,有没有正确的方法来使用流收集器?
解决方法:
如果您不想使用额外的功能,您可以执行以下操作,它可读且易于理解,首先按ID分组,使用列表中的第一个元素创建一个新对象,然后加入所有B的类以最终收集如.
List<A> result = list.stream()
.collect(Collectors.groupingBy(A::getId))
.values().stream()
.map(grouped -> new A(grouped.get(0).getId(), grouped.get(0).getName(),
grouped.stream().map(A::getList).flatMap(List::stream)
.collect(Collectors.toList())))
.collect(Collectors.toList());
另一种方法是使用二元运算符和Collectors.groupingBy方法.这里使用java 8可选类在fst为null时第一次创建新的A.
BinaryOperator<A> joiner = (fst, snd) -> Optional.ofNullable(fst)
.map(cur -> { cur.getList().addAll(snd.getList()); return cur; })
.orElseGet(() -> new A(snd.getId(), snd.getName(), new ArrayList<>(snd.getList())));
Collection<A> result = list.stream()
.collect(Collectors.groupingBy(A::getId, Collectors.reducing(null, joiner)))
.values();
如果你不喜欢在短lambda中使用return(看起来不那么好),唯一的选择是过滤器,因为java没有提供像stream一样的另一种方法(注意:一些IDE突出显示’简化’表达式和突变不应该在过滤器中[但我认为在地图中也不是]).
BinaryOperator<A> joiner = (fst, snd) -> Optional.ofNullable(fst)
.filter(cur -> cur.getList().addAll(snd.getList()) || true)
.orElseGet(() -> new A(snd.getId(), snd.getName(), new ArrayList<>(snd.getList())));
您还可以将此joiner用作通用方法,并使用允许加入使用初始化函数创建的新可变对象的使用者创建一个从左到右的reducer.
public class Reducer {
public static <A> Collector<A, ?, A> reduce(Function<A, A> initializer,
BiConsumer<A, A> combiner) {
return Collectors.reducing(null, (fst, snd) -> Optional.ofNullable(fst)
.map(cur -> { combiner.accept(cur, snd); return cur; })
.orElseGet(() -> initializer.apply(snd)));
}
public static <A> Collector<A, ?, A> reduce(Supplier<A> supplier,
BiConsumer<A, A> combiner) {
return reduce((ign) -> supplier.get(), combiner);
}
}
并使用它
Collection<A> result = list.stream()
.collect(Collectors.groupingBy(A::getId, Reducer.reduce(
(cur) -> new A(cur.getId(), cur.getName(), new ArrayList<>(cur.getList())),
(fst, snd) -> fst.getList().addAll(snd.getList())
))).values();
或者,如果您有一个初始化集合的空构造函数
Collection<A> result = list.stream()
.collect(Collectors.groupingBy(A::getId, Reducer.reduce(A::new,
(fst, snd) -> {
fst.getList().addAll(snd.getList());
fst.setId(snd.getId());
fst.setName(snd.getName());
}
))).values();
最后,如果您已经拥有其他答案中提到的复制构造函数或合并方法,则可以进一步简化代码或使用Collectors.toMap方法.
内容总结
以上是互联网集市为您收集整理的使用Java流合并列表中相同对象下的列表全部内容,希望文章能够帮你解决使用Java流合并列表中相同对象下的列表所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。