私は次のオブジェクトを持っています:
public class Item {
String value;
List<Person> owners;
Person creator;
}
public class Person {
String name;
int id;
Person manager;
}
これで、3つのItemオブジェクトを含むリストができました。
i1 -> {value="1", owners=[p1, p2, p3], creator=p4}
i2 -> {value="2", owners=[p2, p3], creator=p5}
i3 -> {value="3", owners=[p5], creator=p1}
personオブジェクトは次のとおりです。
p1 -> {manager=m1, ...}
p2 -> {manager=m2, ...}
p3 -> {manager=m3, ...}
p4 -> {manager=m2, ...}
p5 -> {manager=m1, ...}
所有者と作成者のマネージャーに基づいて、Itemオブジェクトのストリームをグループ化したい。結果 Map<Person, List<Item>>
は次のようになります:
{
m1: [i1, i2, i3],
m2: [i1, i2],
m3: [i1, i2]
}
StreamAPIとCollectorAPIを使用して、アイテムからマネージャーへのマップを作成できると思います。Map<Item, List<Person>>
最初に、次にマッピングを逆にします。しかし、ストリームとコレクターのみを使用して必要なマッピングを作成する方法はありますか?
これは、個人/マネージャーと元のアイテムとの関連付けを記憶するための中間の「ペア」値でのみ可能だと思います。 Javaの標準APIに標準のペア型がない場合は、Pair
型に最も近いMap.Entry
に頼る必要があります。
Map<Person, List<Item>> map = list.stream()
.flatMap(item->item.getOwners().stream()
.map(p->new AbstractMap.SimpleEntry<>(p.getManager(), item)))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
import static
を使用して改善した後、
Map<Person, List<Item>> map = list.stream()
.flatMap(item->item.getOwners().stream().map(p->new SimpleEntry<>(p.getManager(), item)))
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));
その結果
m1: [i1,i3]
m3: [i1,i2]
m2: [i1,i2]
これは、最初に標準マップに定義された順序がないためです。次に、サンプルデータのm1
がi2
に関連付けられていないため、期待を間違えたと思います。
このようなシナリオは、標準のStream APIを拡張する私の無料の StreamEx ライブラリによって十分にサポートされています。
Map<Person, List<Item>> map = StreamEx.of(list) // create an enhanced stream of Item
// create a stream of Entry<Item, manager>
.cross(item -> item.getOwners().stream().map(Person::getManager))
// swap keys and values to get stream of Entry<manager, Item>
.invert()
.grouping();
内部的には、@ Holgerソリューションに似ています。