web-dev-qa-db-ja.com

ワンライナーでストリーム/リストの最後の要素を取得します

次のコードでストリームまたはリストの最後の要素を取得するにはどうすればよいですか?

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から直接取得できないようです。 (有限ストリームに対してのみ意味があります)
  • また、Listインターフェースからfirst()last()のようなものを取得できないようです。これは本当に苦痛です。

Listインターフェイスでfirst()およびlast()メソッドを提供しないという引数はありません。そこにある要素は順序付けられており、さらにサイズがわかっています。

しかし、元の答えに従って:有限の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を使用する必要があります。これは、パフォーマンスを低下させる可能性があるため、通常は望ましくありません。

90
skiwi

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

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

この実装は、すべての 順序付きストリームLists から作成されたストリームを含む)で機能します。 nordered ストリームの場合、明らかな理由により、どの要素が返されるかは指定されていません。

実装は、sequentialparallelストリームの両方で機能します。それは一見すると驚くかもしれませんが、残念ながらドキュメントには明示的に記載されていません。ただし、これはストリームの重要な機能であり、明確にしようとしています。

  • メソッドのJavadoc Stream :: reduce は、 "がnotに制約されていることを示していますsequentially "を実行します。
  • Javadocでは、 "アキュムレータ関数はassociativenon- interferingstateless2つの値を結合する関数 "、明らかにラムダの場合式(first, second) -> second
  • リダクション操作 のJavadocには次のように記述されています: "ストリームクラスには、 reduce() および collect () [..] "および"適切に構築されたリデュース操作は、本質的に並列化可能です 、要素の処理に使用される関数が 結合 および ステートレス である限り。 "

密接に関連する Collectors のドキュメントはさらに明確です: "sequentialおよび並列実行同等の結果を生成し、コレクター関数はアイデンティティを満たさなければならず、 結合性 制約。 "


元の質問に戻ります。次のコードは、変数lastの最後の要素への参照を格納し、ストリームが空の場合に例外をスローします。複雑さは、ストリームの長さにおいて線形です。

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

コレクション(またはより一般的なIterable)がある場合、Google Guavaの

Iterables.getLast(myIterable)

便利なワンライナーとして。

36
Peti

1つのライナー(ストリームの必要なし;):

Object lastElement = list.get(list.size()-1);
9
nimo23

グアバには、このケース専用の方法があります。

Stream<T> stream = ...;
Optional<T> lastItem = Streams.findLast(stream);

stream.reduce((a, b) -> b)と同等ですが、作成者はパフォーマンスがはるかに優れていると主張しています。

ドキュメント から:

このメソッドの実行時間はO(log n)とO(n)の間であり、効率的に分割可能なストリームでパフォーマンスが向上します。

ストリームが順序付けられていない場合、このメソッドはfindAny()のように動作することに注意してください。

1
k13i