使用java8映射对象

时间:2016-11-03 22:44:22

标签: java java-8 java-stream

我们说我有一个Foo对象列表。 Foo上有一个属性,我必须使用它从数据源中获取Bar对象。然后我必须将每个bar对象映射回我为Bar获取的原始Foo对象。

public class Foo {
   int barId;
}

public class Bar {
   int barId;
}

Set<Foo> inputFoo;
Map<Bar, Foo> barToFoo;

public Bar getBar(int barId);

我的尝试如下:

List<Bar> allBarsInFoo = inputFoos.stream()
.map(Foo::barId)
.forEach(b -> getBar(b))

我不知道如何在没有做更多沉重和不必要的操作之后获取Bar to Foo的地图。

编辑:为了使我的问题更加通用,有没有办法保持对原始对象的引用,在原始对象列表中的流中执行一堆过滤器/映射操作,然后映射结果过滤/映射作为键,将原始对象作为结果映射的值?

2 个答案:

答案 0 :(得分:2)

我认为Collectors.toMap()是您正在寻找的:

Map<Bar, Foo> barToFoo = inputFoo.stream()
        .collect(Collectors.toMap(f -> getBar(f.barId), Function.identity()));

答案 1 :(得分:1)

您似乎想要一张反向地图或一张地图,其中每个值都指向它的关键字。这有一些问题,第一个是数学地图(有时表示为函数)不能保证是一个数学身份(这是一种说明函数具有反函数的奇特方式)。

因此,获取A的键并提供B的值的地图看起来像

f(A) -> B

但是有很多地图,人们不能写它反向并且反转仍然是函数

f'(B) -> A (only exists for some functions)

例如

f(x) = x*x

让我们使用输入

f(0) = 0
f(1) = 1
f(2) = 4

以及

f(-1) = 1
f(-2) = 4

所以反函数必须要做

f'(0) = 0 (the zero's are swapped compared to the above example)
f'(1) = 1 or -1 (sorry, but that's not valid output for a function)
f'(4) = 2 or -2 (ditto)

这意味着地图通常不可逆。但是,如果您将键入放宽到几乎相反的位置,则可以生成广义逆:

Map<Foo, Bar> x
(back maps to)
Map<Bar, Collection<Foo>> y;

流式传输API是一件好事,但在这种情况下,它可能无法为您提供最简单的解决方案。

Map <Bar, Set<Foo>> backmap = new HashMap<>();
for (Map.Entry<Foo, Bar> entry : barToFoo.entrySet()) {
    if (backmap.contains(entry.getValue()) {
        backmap.get(entry.getValue()).add(entry.getKey());
    } else {
        backmap.put(entry.getValue(), new HashSet<Foo>(entry.getKey));
    }
}