6

以下のようなコレクションがあり、月末ではない日付以外のすべてを除外したいと考えています。

2010-01-01=2100.00, 
2010-01-31=2108.74, 
2010-02-01=2208.74, 
2010-02-28=2217.92, 
2010-03-01=2317.92, 
2010-03-31=2327.57, 
2010-04-01=2427.57, 
2010-04-30=2437.67, 
2010-05-01=2537.67, 
2010-05-31=2548.22, 
2010-06-01=2648.22, 
2010-06-30=2659.24, 
2010-07-01=2759.24, 
2010-07-31=2770.72, 
2010-08-01=2870.72, 
2010-08-31=2882.66, 
2010-09-01=2982.66, 
2010-09-30=2995.07, 
2010-10-01=3095.07, 
2010-10-31=3107.94, 
2010-11-01=3207.94, 
2010-11-30=3221.29

次のフィルター基準があります。指定された の一致する月末をfrequency.getEnd返します。LocalDateLocalDate

.filter(p -> frequency.getEnd(p.getKey()) == p.getKey())

したがって、このフィルタリングされたストリームをマップに戻す必要があると思います。そして、それを行うためにコレクターを使用していると思います。したがって、私は追加します:

.collect(Collectors.toMap(/* HUH? */));

しかし、私は何をすべきかわかりませんCollectors.toMap。例を読むと混乱します。これが明らかに機能しない私の現在のコードです。

TreeMap<LocalDate, BigDecimal> values = values.entrySet()
                                              .stream()
                                              .filter(p -> frequency.getEnd(p.getKey()) == p.getKey())
                                              .collect(Collectors.toMap(/* HUH? */));
4

4 に答える 4

25

あなたの問題を次のように考えてください: マップのエントリのストリーム、つまり があり、Stream<Map.Entry<LocalDate, BigDecimal>>それを に集めたいとしますTreeMap<LocalDate, BigDecimal>

したがって、あなたは正しいです。使用する必要がありますCollectors.toMap現在、ドキュメントでわかるようにCollectors.toMap、引数に応じて、実際には 3 があります。

  • toMap(keyMapper, valueMapper). keyMapper入力がストリームの現在の要素であり、出力が最終 Map のキーである関数です。したがって、Stream 要素をキーにマップします (したがって、名前が付けられます)。valueMapper入力がストリームの現在の要素であり、出力が最終 Map の値である関数です。
  • toMap(keyMapper, valueMapper, mergeFunction). 最初の 2 つのパラメーターは以前と同じです。3 番目のmergeFunctionは、最終的な Map でキー要素が重複している場合に呼び出される関数です。したがって、その入力は 2 つの値 (つまり、keyMapper同じキーを返す 2 つの値) であり、これら 2 つの値を 1 つの値にマージします。
  • toMap(keyMapper, valueMapper, mergeFunction, mapSupplier). 最初の 3 つの引数は以前と同じです。4 番目は Map のサプライヤです。現在 JDK に実装されているため、前の 2 つtoMapはインスタンスを返しHashMapます。ただし、特定の Map インスタンスが必要な場合、このサプライヤはそのインスタンスを返します。

この特定のケースではtoMap、結果の Map を明示的に にしたいので、3 番目の を使用する必要がありTreeMapます。どのような入力を与えるべきか見てみましょう:

  • keyMapper: したがって、これは最終的なマップのキーを返す必要があります。ここでは a を扱っているStream<Map.Entry<LocalDate, BigDecimal>>ので、各 Stream 要素は typeMap.Entry<LocalDate, BigDecimal>です。この関数は、Map.Entry<LocalDate, BigDecimal> e入力として a を受け取ります。その出力は、最終的な Map のキーである必要があります。この場合、出力はe.getKey()、つまりLocalDateエントリが保持している である必要があります。これは、ラムダ式として記述できます: e -> e.getKey(). これはメソッド参照として書くこともできますMap.Entry::getKeyが、理解しやすいかもしれないので、ここではラムダに固執しましょう。
  • valueMapper: これは上記と同じですが、この場合、この関数はe.getValue()、つまりBigDecimalエントリが保持している を返す必要があります。これはe -> e.getValue()です。
  • mergeFunction: これは難しい問題です。LocalDate構造上、最終的な Map には重複するキー要素がない (つまり、重複しない) ことがわかっています。ここに何を書きますか?簡単な解決策は、例外をスローすることです。これは発生すべきではありません。発生した場合は、どこかに大きな問題があります。したがって、2 つの入力引数が何であれ、例外をスローします。これは のように書くことができます(v1, v2) -> { throw new SomeException(); }。括弧で囲む必要があることに注意してください。この場合、JDK が現在行っていることと一致さSomeExceptionせるために、IllegalStateException.
  • mapSupplier: 前に述べたように、 を提供したいと考えていTreeMapます。サプライヤーは引数を取らず、新しいインスタンスを返します。したがって、これは次のように記述でき() -> new TreeMap<>()ます。ここでも、メソッド参照と write を使用できますTreeMap::new

ストリームの収集部分を記述した最終コード (上記のように、このコードでは、対応するメソッド参照も使用できることに注意してください。コメントに追加しました):

Collectors.toMap(
       e -> e.getKey(),    // Map.Entry::getKey
       e -> e.getValue(),  // Map.Entry::getValue
       (v1, v2) -> { throw new IllegalStateException(); },
       () -> new TreeMap<>())  // TreeMap::new
)
于 2015-11-15T20:58:06.043 に答える
4

Map.Entry値を反復しているtoMap()ため、キーと値を抽出するための 2 つのメソッドが必要なだけなので、次のように簡単です。

Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)

これはを返さないTreeMapことに注意してください。そのためには、次のものが必要です。

Collectors.toMap(Entry::getKey,
                 Entry::getValue,
                 (v1,v2) -> { throw new IllegalStateException("Duplicate key"); },
                 TreeMap::new)
于 2015-11-15T20:53:53.853 に答える
1

最も単純な形式の toMap メソッドは 2 つの引数を取ります。1 つは入力をキーにマップする関数で、もう 1 つは入力を値にマップする関数です。両方の関数の出力が組み合わされて、結果のマップのエントリが形成されます。

次のようなことをする必要があると思います:

Collectors.toMap(p -> p.getKey(), p -> p.getValue())
于 2015-11-15T20:55:24.150 に答える