Guava:Lists.filter()関数がないのはなぜですか?


86

理由はありますか

Lists.transform()

しかし、

Lists.filter()

リストを正しくフィルタリングするにはどうすればよいですか?使用できます

new ArrayList(Collection2.filter())

もちろんですが、この方法では、正しく理解していれば、注文が同じであるとは限りません。


8
参考までに、List.newArrayList(Iterables.filter(...))は、通常、new ArrayList(Collection2.filter(...))よりも高速です。ArrayListコンストラクターはフィルター処理されたコレクションでsize()を呼び出し、サイズを計算するには、元のリストのすべての要素にフィルターを適用する必要があります。
Jared Levy 2011

4
@JaredLevyたぶん、の代わりにList.newArrayList(Iterables.filter(...))、と言うべきLists.newArrayList(Iterables.filter(...)) です。
アブダル2013

回答:


57

返されたリストビューの#get(index)など、危険な多数の低速メソッドが公開されるため、実装されませんでした(パフォーマンスのバグを招きます)。また、ListIteratorも実装するのが面倒です(パッチを提出しましたがをカバーするために数年前に)。

インデックス付きのメソッドは、フィルター処理されたリストビューでは効率的ではないため、フィルター処理されたIterableを使用することをお勧めします。


7
リストビューが返されると想定しています。ただし、#filterは、新しいマテリアライズされたリストを返すように実装できます。これは、Iterableのフィルターメソッドではなく、リストのフィルターメソッドに実際に期待するものです。
Felix Leipold 2015年

@FelixLeipoldしかし、これは水を濁らせるでしょう。それがあるとして、filter一貫しているのかどうか(意味の行動と一緒に)ビューを意味しIterables.filterSets.filterなどがあるのでIterables.filter簡単でコンバインcopyOfの任意のImmutableCollection、私が見つけ、この優れた設計のトレードオフ(のような余分なメソッド&名、を考え出す対filteredCopyまたはその他もろもろ、単純なユーティリティの組み合わせの場合)。
ルークアッシャーウッド2018

37

使用できます Iterables.filter。これにより、確実に順序が維持されます。

新しいリストを作成すると、要素(もちろん参照のみ)がコピーされることに注意してください。そのため、元のリストへのライブビューにはなりません。ビューの作成にはかなり注意が必要です。次の状況を考慮してください。

Predicate<StringBuilder> predicate = 
    /* predicate returning whether the builder is empty */
List<StringBuilder> builders = Lists.newArrayList();
List<StringBuilder> view = Lists.filter(builders, predicate);

for (int i = 0; i < 10000; i++) {
    builders.add(new StringBuilder());
}
builders.get(8000).append("bar");

StringBuilder firstNonEmpty = view.get(0);

それは、すべてにフィルターを適用して、元のリスト全体を反復処理する必要があります。ビューの存続期間中に述語の一致が変化しないことが必要になる可能性があると思いますが、それでは完全に満足できるものではありません。

(これは単なる推測です、気をつけてください。たぶん、グアバのメンテナの1人が本当の理由でチップインするでしょう:)


1
Collections2.filter.iteratorを呼び出すだけなIterables.filterので、結果は同じです。
skaffman 2011

@skaffman:その場合Iterables.filter、わかりやすくするためにバージョンを使用します。
Jon Skeet 2011

3
...view.size()コードの後半で必要な場合を除いて:)
Xaerxess 2011

28

new List(Collection2.filter())もちろん使用することもできますが、この方法では、注文が同じであるとは限りません。

これは真実ではありません。 Collections2.filter()は遅延評価された関数です。フィルタリングされたバージョンへのアクセスを開始するまで、実際にはコレクションをフィルタリングしません。たとえば、フィルター処理されたバージョンを反復処理すると、フィルター処理された要素は、元のコレクションと同じ順序でイテレーターからポップアウトされます(明らかにフィルター処理された要素を除く)。

おそらく、事前にフィルタリングを実行し、その結果を何らかの形式の任意の順序付けられていないコレクションにダンプすると考えていたのかもしれませんが、そうではありません。

したがって、の出力をCollections2.filter()新しいリストへの入力として使用する、元の順序保持されます。

静的インポート(およびLists.newArrayList関数)を使用すると、かなり簡潔になります。

List filteredList = newArrayList(filter(originalList, predicate));

注しばらくはことをCollections2.filter熱心に基になるコレクションを反復処理しません、Lists.newArrayList します-それは、フィルター処理されたコレクションのすべての要素を抽出し、新しいにそれらをコピーしますArrayList


それはもっと似ています:List filteredList = newArrayList(filter(originalList, new Predicate<T>() { @Override public boolean apply(T input) { return (...); } }));またはすなわち。List filteredList = newArrayList(filter(originalList, Predicates.notNull()));
xaerxess 2011

@Xaerxess:おっと、はい、述語を忘れました...修正済み
skaffman 2011

@Bozho:ありがとう...私は十分に時間がかかりました:)
skaffman 2011

12

Jonが述べたように、Iterables.filter(..)またはCollections2.filter(..)を使用できます。ライブビューが必要ない場合は、ImmutableList.copyOf(Iterables.filter(..))またはLists.newArrayList( Iterables.filter(..))を使用できます。はい、順序は維持されます。 なぜその部分に

本当に興味がある場合は、https://github.com/google/guava/issues/505にアクセスして詳細を確認できます


6

他の人が言ったことを要約すると、リストをフィルタリングするための汎用ラッパーを簡単に作成できます。

public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) {
    return Lists.newArrayList(Iterables.filter(userLists, predicate));
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.