2016-11-03 3 views
0

私はFooオブジェクトのリストを持っているとしましょう。 Fooには、データソースからBarオブジェクトを取得するために使用する必要があるプロパティがあります。私はBarオブジェクトを元のFooオブジェクトにマップする必要があります。java8を使ったオブジェクトのマッピング

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)) 

私は上記の後、より重いと不必要なオペレーションを行うことなく、fooへのバーのマップを取得する方法がわかりません。

編集:私の質問をもっと一般的にするには、元のオブジェクトへの参照を保持し、元のオブジェクトのリストから離れたストリームで一連のフィルタ/マップ操作を実行し、キーとしてフィルター/マップ、結果のマップの値として元のオブジェクト?

+0

重く不必要な計算については、ご注意ください。 Javaでは、計算の数はタイピングの量と密接に関連していません。ソリューションを書くのが短くても、ベンチマークではなくパフォーマンスが良いとは思わないでください。 Javaが最適化しなければならないすべての機会で、ベンチマークだけがどのアプローチがより速いかを本当に教えてくれるでしょう。 –

答えて

2

私はCollectors.toMap()は、あなたが探しているものだと思う:

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

私の例外で、getBarがnull値を返した場合、それらをフィルタリングしたい場合はどうなりますか?私は.filter(Objects :: nonnull)を使用したいと思います。どうやってやるの? –

+0

@JohnBaum Java 9には['filtering()'](http://download.java.net/java/jdk9/docs/api/java/util/stream/Collectors.html#filtering-java.util.function)があります。 .Predicate-java.util.stream.Collector-)コレクタがありますが、Java 8では、通常のループを守る方がよいでしょう。 – shmosel

+0

オプションのでgetBarをラップし、ストリーム内でフィルタリングすることができます – Veeram

1

あなたが逆のマップ、または戻ってのキーに各値ポイントマップを望んでいるようです。これにはいくつかの問題がありますが、数学的なマップ(関数として表現されることもあります)が数学的アイデンティティーであることが保証されていないことが最初のものです。

だから、Aのキーを受け取り、Bの値を提供するマップが

f(A) -> B 

のように見えるしかし、一つは、それは逆だ書き、逆はまだ

f'(B) -> A (only exists for some functions) 
機能も持つことができない多くのマップがあります 例えば

f(x) = x*x 

1の入力を使用することができます

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)); 
    } 
} 
+2

私は逆マップが質問とは関係ないとは思わない。 OPは 'Bar'を' Foo'にマッピングしたいと思っていて、それをストリームでどのように理解しようとしています。 – shmosel

+0

@shmosel Foo to Barのマップとして開始すると、Bar to Fooのマップは最初の入力の逆マップです。 –

+0

はい、OPでは逆マップは必要ありません。 – shmosel

関連する問題