Java 使用流将列表转换为另一个列表

Java 使用流将列表转换为另一个列表,java,java-stream,Java,Java Stream,鉴于 我想把它转换成 {[Foo [id=1, name=a, category=c1, categories=null], Foo [id=1, name=a, category=c2, categories=null]], [Foo [id=2, name=a, category=c1, categories=null]]} i、 e.将单个类别整理成类别列表 这是目前的代码,实现了我想要的 [Foo [id=1, name=a, category=null, categories=[c1

鉴于

我想把它转换成

{[Foo [id=1, name=a, category=c1, categories=null], Foo [id=1, name=a, category=c2, categories=null]], [Foo [id=2, name=a, category=c1, categories=null]]}
i、 e.将单个
类别
整理成
类别列表

这是目前的代码,实现了我想要的

[Foo [id=1, name=a, category=null, categories=[c1, c2]], Foo [id=2, name=a, category=null, categories=[c1]]]
publicstaticvoidmain(最终字符串[]args){
最终Foo f1=新Foo(1L,“a”,“c1”);
最终Foo f2=新的Foo(1L,“a”,“c2”);
最终Foo f3=新的Foo(2L,“a”,“c1”);
最终列表li=列表(f1、f2、f3);
li.forEach(e->System.out.println(e));
final-Map-collect=li.stream().collect(Collectors.groupingBy(Foo::getId));
系统输出打印项次(收集);
最终列表分组=新建ArrayList();
collect.forEach((k,v)->{
系统输出
.println(“key=“+k+”val=“+v.stream().map(e1->e1.getCategory()).collect(Collectors.toList()));
final Foo-Foo=collect.get(k).get(0);
setCategories(v.stream().map(e1->e1.getCategory()).collect(Collectors.toList());
foo.setCategory(空);
添加(foo);
});
系统输出打印项次(分组);
}
是否有任何方法可以单独使用streams&lambdas而不必分成多个步骤?目标是使此代码更加优雅、可读,并向读者传达意图


这个问题在本质上与我类似,但对我没有帮助,因为这里是聚合,而这里不是聚合。

可以通过实现一个
合并
函数来完成,该函数将在类别列表中累积类别,然后使用流的
减少
操作:

class-Foo{
静态Foo合并(Foo累计、Foo其他){
if(null==累计类别){
accum.categories=新的ArrayList();
如果(空!=累计类别){
累计类别新增(累计类别);
累计类别=空;
}
}
累计类别新增(其他类别);
返回累计;
}
}
实施:

静态列表joinedCategoriesReduce(列表输入){
返回输入
.stream()
.collect(Collectors.groupingBy(Foo::getId))//映射
.values().stream()//流
.map(v->v.stream()//流
.reduce(新的Foo(v.get(0).getId(),v.get(0).getName(),(字符串)null),Foo::merge)
)
.collect(Collectors.toList());
}
试验


另一个选项是提供接受类别列表的Foo构造函数:

//类Foo
公共Foo(长id、字符串名称、列表猫){
this.id=id;
this.name=名称;
这个类别=猫;
}
然后,可以使用类别列表轻松地将映射条目重新映射到
Foo
实例:

静态列表joinedCategoriesMap(列表输入){
返回输入
.stream()
.collect(收集器.groupingBy(Foo::getId))
.values().stream()
.map(v->newfoo(
v、 get(0.getId(),
v、 get(0).getName(),
v、 stream().map(Foo::getCategory).collect(Collectors.toList())
)
.collect(Collectors.toList());
}

严格按照流和lambda重新表示计算通常是可能的,但在许多情况下,结果不那么优雅,更难阅读,而且不可测量。越难理解这样的转换,就越有可能是您朝着与既定目标相关的错误方向前进。仅供参考,当您希望改进工作代码时,更合适。@jaco0646一个我不知道存在(或不知道是专门构建的)的全新世界!非常感谢。谢谢亚历克斯的回答。这肯定是朝着我的目标。然而,你真的得到了你发布的o/p吗?我得到了一个不同的o/p
Foo[id=1,name=a,category=null,categories=null,c2]]Foo[id=2,name=a,categories=null,categories=null,categories=[null]]
看起来身份中的
null
搞乱了一些东西。是的,正如我写的那样,你可以查看到在线演示的链接:在最后的代码片段中,分组后,您可以流化值,而不是条目。我觉得简单一点,我的错!由于我这边的一个错误,我得到了
null,c2
。我已经采纳了你上次的建议,并对其稍作修改。我没有使用构造函数,而是使用了两种方法来完成这项工作。我正在探索这个选项,因为我的对象
Foo
可能不是一个只有3个成员的傻瓜。它可能有一大堆成员。这是它的理由。如果没有太多的要求,你可以看一看,让我知道你是否有任何f/b?这是值得的,使
copyWithoutCategories
静态和使方法
populateCategories
返回
Foo
的当前实例,以流畅的方式在
StringBuilder
中进行链式调用,这样就可以简化
{Foo modified=…;return modified;}
part,如图所示
{[Foo [id=1, name=a, category=c1, categories=null], Foo [id=1, name=a, category=c2, categories=null]], [Foo [id=2, name=a, category=c1, categories=null]]}
[Foo [id=1, name=a, category=null, categories=[c1, c2]], Foo [id=2, name=a, category=null, categories=[c1]]]
public static void main(final String[] args) {
        final Foo f1 = new Foo(1L, "a", "c1");
        final Foo f2 = new Foo(1L, "a", "c2");
        final Foo f3 = new Foo(2L, "a", "c1");

        final List<Foo> li = List.of(f1, f2, f3);
        li.forEach(e -> System.out.println(e));

        final Map<Long, List<Foo>> collect = li.stream().collect(Collectors.groupingBy(Foo::getId));
        System.out.println(collect);

        final List<Foo> grouped = new ArrayList<>();
        collect.forEach((k, v) -> {
            System.out
                    .println("key=" + k + "val=" + v.stream().map(e1 -> e1.getCategory()).collect(Collectors.toList()));

            final Foo foo = collect.get(k).get(0);
            foo.setCategories(v.stream().map(e1 -> e1.getCategory()).collect(Collectors.toList()));
            foo.setCategory(null);

            grouped.add(foo);
        });

        System.out.println(grouped);
    }
final Foo f1 = new Foo(1L, "a", "c1");
final Foo f2 = new Foo(1L, "a", "c2");
final Foo f3 = new Foo(2L, "a", "c1");

final List<Foo> li = List.of(f1, f2, f3);
joinedCategoriesReduce(li).forEach(System.out::println);
Foo(id=1, name=a, category=null, categories=[c1, c2])
Foo(id=2, name=a, category=null, categories=[c1])