1. ホーム
  2. java

[解決済み] ワンライナーでストリーム/リストの最後の要素を取得する

2022-05-12 20:18:15

質問

以下のコードで、ストリームやリストの最後の要素を取得するにはどうしたらよいでしょうか。

ここで data.careasList<CArea> :

CArea first = data.careas.stream()
                  .filter(c -> c.bbox.orientationHorizontal).findFirst().get();

CArea last = data.careas.stream()
                 .filter(c -> c.bbox.orientationHorizontal)
                 .collect(Collectors.toList()).; //how to?

最初の要素を取得するとわかるように、ある特定の filter で、最初の要素を取得することは難しくありません。

しかし、ワンライナーで最後の要素を取得するのは本当に大変なことです。

  • から直接取得することはできないようです。 Stream . (それは有限のストリームに対してのみ意味をなすでしょう)
  • のようなものも取得できないようです。 first()last() から List インターフェイスに変換する必要があり、これは本当に面倒です。

を提供しないことに対する反論は見当たりません。 first()last() メソッドを List インターフェイスにある要素は順番に並べられ、さらにサイズもわかっています。

しかし、元の答えのように の最後の要素を得るにはどうしたらよいでしょうか? Stream ?

個人的には、これが一番近いかな。

int lastIndex = data.careas.stream()
        .filter(c -> c.bbox.orientationHorizontal)
        .mapToInt(c -> data.careas.indexOf(c)).max().getAsInt();
CArea last = data.careas.get(lastIndex);

ただし、この場合 indexOf を使うことになりますが、これはパフォーマンスを低下させる可能性があるので、一般的には好ましくないでしょう。

どのように解決するのですか?

最後の要素を取得するためのメソッドとして ストリーム::reduce . 次のリストには、一般的な場合の最小限の例が含まれています。

Stream<T> stream = ...; // sequential or parallel stream
Optional<T> last = stream.reduce((first, second) -> second);

この実装は、すべての 順序付きストリーム (から作成されたストリームを含む)。 リスト ). については 順不同 ストリームでは、明白な理由により、どの要素が返されるかは指定されていません。

この実装は シーケンシャル そして 並列ストリーム . これは一見すると驚くべきことかもしれませんし、残念ながらドキュメントには明示的に書かれていません。しかし、これはストリームの重要な機能であり、私はそれを明確にするよう努めます。

  • メソッドの Javadoc は ストリーム::リデュース には、以下のように書かれています。 です。 ではない を実行する制約があります。 シーケンシャル "です。 .
  • また、Javadocでは "アキュムレータ関数は必ず 連想 , 非干渉型 , ステートレス 2つの値を組み合わせるための関数" これは明らかにラムダ式の場合です。 (first, second) -> second .
  • の Javadoc は 削減操作 の状態になります。 "ストリームクラスは、一般的な還元操作の複数の形式を持ち、これを reduce() collect() [...]" "適切に構築されたreduceオペレーションは 本質的に並列化可能であり である限り、要素を処理するために使用される関数(複数可)が 連想的 であり ステートレス ."

密接に関連する コレクター のドキュメントはさらに明確です。 を確実にするために シーケンシャル 並列実行 を生み出す 同等の結果 の場合、コレクター関数は ID と 連想性 制約."を満たす必要があります。


元の質問に戻ります。次のコードは、最後の要素への参照を変数に格納します。 last に格納し、ストリームが空であれば例外を投げる。複雑さはストリームの長さに比例します。

CArea last = data.careas
                 .stream()
                 .filter(c -> c.bbox.orientationHorizontal)
                 .reduce((first, second) -> second).get();