转换地图<long,list <foo =“”>&gt;列出<foo>

时间:2015-08-19 09:45:37

标签: java algorithm java-8

我有这样的结构:

Map<Long, List<Foo>>

其中类Foo公开方法:

Class Foo {
     public List<Bar> getBars();
     public void setBars(List<Bar> bars);
}

现在我想将此地图转换为List参数化Foo类,其中此列表中的每个项目都是Foo实例,其中包含给定长值的聚合条形列表。例如,使用map:

{1: [Foo1, Foo2],
 2: [Foo3]}

其中

Foo1.bars = [Bar1, Bar2]
Foo2.bars = [Bar3]
Foo3.bars = [Bar4, Bar5]

我希望得到结果:

[FooA, FooB]

,其中

FooA.bars = [Bar1, Bar2, Bar3]
FooB.bars = [Bar4, Bar5]

Java 8中最优雅的解决方案是什么? 如果需要,可以重复使用map中的一些Foo实例,因为在此操作之后它们不再被使用。

1 个答案:

答案 0 :(得分:5)

假设你有一个Foo(List<Bar> bars)构造函数,那很简单:

import static java.util.stream.Collectors.*;

List<Foo> result = map.values()
    .stream()
    .map(
        foos -> new Foo(foos.stream()
                    .flatMap(foo -> foo.getBars().stream())
                    .collect(toList())))
    .collect(toList());

我们获取原始地图值的流(我们不关心密钥),它们是Foo的列表。我们将每个此类列表展平以获取Bar的流,将它们收集到列表并将此列表传递给Foo(List<Bar>)构造函数,以便我们获取新的Foo个对象。最后,我们将它们收集到List

如果您没有Foo(List<Bar>),只有setter,则应首先创建一个空的Foo,然后使用setter并返回创建的Foo

List<Foo> result = map.values()
    .stream()
    .map(foos -> {
            Foo f = new Foo();
            f.setBars(foos.stream().flatMap(
                foo -> foo.getBars().stream()).collect(toList()));
            return f;
        })
    .collect(toList());

如果您不想创建新的Foo对象(例如,您希望保留其他属性),最好不要引入setBars,而是addBars方法(为现有的添加新的条形图),如下所示:

public class Foo {
    ...
    public Foo addBars(List<Bar> bars) {
        this.bars.addAll(bars);
        return this;
    }
}

现在您可以使用reduce终端操作来组合foos:

List<Foo> result = map.values()
        .stream()
        .map(foos -> foos.stream()
             .reduce((foo1, foo2) -> foo1.addBars(foo2.getBars())).get())
        .collect(toList());