web-dev-qa-db-ja.com

ストリームフィルターの時間の複雑さ

私はこのようなコードを持っています:

List<Listing> Listings = new ArrayList<>();
Listings.add(listing1);
Listings.add(listing2);
...
...
...

Listing listing= listings.stream()
                .filter(l -> l.getVin() == 456)
                .findFirst();

私の質問は、フィルター処理の時間の複雑さは何ですか? O(n)の場合、私の直感は、データ構造のようなHashSetに変換して、時間の複雑さがO(1)になるようにすることです。これをストリームで行うエレガントな方法はありますか?

11
zonyang

O(n)です。ストリームフィルタリングは内部的に反復を使用します。

次のようにマップに変換できます。

Map<Integer, Listing > mapOfVinToListing = listings.stream().collect(Collectors.toMap(Listing::getVin, Functions.identity()); // Assuming vin is unique per listing
mapOfVinToListing.get(456);// O(1)

ただし、その変換プロセスもO(n)です。したがって、これを一度だけ行う必要がある場合は、フィルターを使用します。同じリストを何度も照会する必要がある場合は、それをマップに変換するのが理にかなっています。

並列ストリームを使用することもできます。場合によってはパフォーマンスが向上することもありますが、それは正確な状況に大きく依存します。

7
Adam

最悪のケースはO(n)ですが、Streamは遅延であるため、値が以前に見つかった場合は、反復が停止します。一定の時間ルックアップが必要な場合は、常に、Mapに変換することをお勧めしますが、追加のスペースが必要になります。リストが巨大な場合、その側面を考慮する必要があります。実際、リストが小さい場合、タイムクリティカルなシステムで作業しているのでない限り、MapListの違いはほとんど目立ちません。

2
Abhijit Sarkar

filter自体なし端末操作はオーバーヘッドがゼロになります-まったく何もしないためです。ストリームは端末操作によってのみ駆動されます-端末操作はなく、何も実行されません。

次に、filterがすべての要素(潜在的にすべて)に対してiterateでなければならない場合がありますソースの(遅延)。したがって、フィルターの時間の複雑さは、ストリーミング元のソースによって異なります。あなたのケースではListなので、O(n)になります。

しかし、それは最悪の場合です。 filter一般的にについては、根本的なソースに依存しているため、平均的なケースを予測することはできません。

2
Eugene