回答:
Java 8(2014)は、1行のコードでストリームとラムダを使用してこの問題を解決します。
List<Person> beerDrinkers = persons.stream()
.filter(p -> p.getAge() > 16).collect(Collectors.toList());
こちらがチュートリアルです。
Collection#removeIf
所定の場所でコレクションを変更するために使用します。(注意:この場合、述語は述語を満たすオブジェクトを削除します):
persons.removeIf(p -> p.getAge() <= 16);
lambdajでは、ループや内部クラスを記述せずにコレクションをフィルタリングできます。
List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
greaterThan(16)));
もっと読みやすいものを想像できますか?
免責事項:私はlambdajの寄稿者です
persons.removeIf(p -> p.getAge() <= 16);
Java 1.5を使用していて、Googleコレクションを追加できないと仮定すると、Googleの担当者が行ったのと非常によく似たことを行います。これはジョンのコメントのわずかなバリエーションです。
まず、このインターフェイスをコードベースに追加します。
public interface IPredicate<T> { boolean apply(T type); }
その実装者は、特定の述語が特定のタイプに当てはまる場合に応答できます。例えばもしはT
なかったUser
とAuthorizedUserPredicate<User>
道具はIPredicate<T>
、その後AuthorizedUserPredicate#apply
に合格したかどうかを返しますUser
許可されています。
次に、いくつかのユーティリティクラスでは、
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
したがって、上記を使用していると仮定すると、
Predicate<User> isAuthorized = new Predicate<User>() {
public boolean apply(User user) {
// binds a boolean method in User to a reference
return user.isAuthorized();
}
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);
線形チェックのパフォーマンスが問題になる場合は、ターゲットコレクションを持つドメインオブジェクトが必要になる場合があります。ターゲットコレクションを持つドメインオブジェクトには、ターゲットコレクションを初期化、追加、設定するメソッドのフィルタリングロジックがあります。
更新:
ユーティリティクラス(たとえば、Predicate)で、述語が期待値を返さない場合のデフォルト値のオプションを備えたselectメソッドと、新しいIPredicate内で使用されるparamsの静的プロパティも追加しました。
public class Predicate {
public static Object predicateParams;
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element : target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
T result = null;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
T result = defaultValue;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
}
次の例では、コレクション間で欠落しているオブジェクトを探します。
List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
new IPredicate<MyTypeA>() {
public boolean apply(MyTypeA objectOfA) {
Predicate.predicateParams = objectOfA.getName();
return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
public boolean apply(MyTypeB objectOfB) {
return objectOfB.getName().equals(Predicate.predicateParams.toString());
}
}) == null;
}
});
次の例では、コレクション内のインスタンスを検索し、インスタンスが見つからない場合は、コレクションの最初の要素をデフォルト値として返します。
MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));
更新(Java 8リリース後):
私(アラン)が最初にこの回答を投稿してから数年になりますが、私はこの回答のSOポイントを集めているとはまだ信じられません。いずれにせよ、Java 8が言語にクロージャーを導入したので、私の答えはかなり異なり、より単純になります。Java 8では、明確な静的ユーティリティクラスは必要ありません。したがって、述語に一致する最初の要素を見つけたい場合。
final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).findFirst();
optionalsのためのJDK 8 APIは、能力にありget()
、isPresent()
、orElse(defaultUser)
、orElseGet(userSupplier)
とorElseThrow(exceptionSupplier)
だけでなく、このような他の「モナド」機能map
、flatMap
およびをfilter
。
述語に一致するすべてのユーザーを単純に収集する場合は、を使用しCollectors
て、目的のコレクションでストリームを終了します。
final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).collect(Collectors.toList());
Java 8ストリームの動作の例については、こちらをご覧ください。
val authorized = for (user <- users if user.isAuthorized) yield user
Apache CommonsのCollectionUtils.filter(Collection、Predicate)を使用します。
「最善の」方法は要求が広すぎます。「最短」ですか?「最速」?「読みやすい」?適切な場所にフィルターをかけますか、それとも別のコレクションに入れますか?
最も簡単な(ただし、ほとんどの場合は読みにくい)方法は、それを反復してIterator.remove()メソッドを使用することです。
Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
Foo foo = it.next();
if( !condition(foo) ) it.remove();
}
これを読みやすくするために、ユーティリティメソッドにラップできます。次に、IPredicateインターフェースを作成し、そのインターフェースの匿名実装を作成して、次のようにします。
CollectionUtils.filterInPlace(col,
new IPredicate<Foo>(){
public boolean keepIt(Foo foo) {
return foo.isBar();
}
});
ここで、filterInPlace()はコレクションを反復処理し、Predicate.keepIt()を呼び出して、インスタンスをコレクションに保持するかどうかを確認します。
このタスクのためだけにサードパーティのライブラリを導入する正当な理由は本当にわかりません。
stream()
機能がありますが、誰もが最新のおもちゃで遊べるわけではありません:P
ジェネリックをサポートする更新されたコレクションフレームワークについては、Googleコレクションを検討してください。
更新:Googleコレクションライブラリは非推奨になりました。代わりにGuavaの最新リリースを使用してください。述語に基づくフィルタリングのメカニズムを含む、コレクションフレームワークに対する拡張機能はすべて同じです。
Java 8を待つ:
List<Person> olderThan30 =
//Create a Stream from the personList
personList.stream().
//filter the element to select only those with age >= 30
filter(p -> p.age >= 30).
//put those filtered elements into a new List.
collect(Collectors.toList());
Java 8の初期リリース以来、次のようなことを試すことができます。
Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);
たとえば、整数のリストがあり、10より大きい数値をフィルタリングして、それらの数値をコンソールに出力したい場合は、次のようにします。
List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
RxJavaをリングに投げます。これはAndroidでも使用できます。RxJavaが常に最適なオプションであるとは限りませんが、コレクションにさらに変換を追加したり、フィルタリング中にエラーを処理したりする場合は、柔軟性が向上します。
Observable.from(Arrays.asList(1, 2, 3, 4, 5))
.filter(new Func1<Integer, Boolean>() {
public Boolean call(Integer i) {
return i % 2 != 0;
}
})
.subscribe(new Action1<Integer>() {
public void call(Integer i) {
System.out.println(i);
}
});
出力:
1
3
5
RxJavaの上の詳細はfilter
見つけることができるここに。
セットアップ:
public interface Predicate<T> {
public boolean filter(T t);
}
void filterCollection(Collection<T> col, Predicate<T> predicate) {
for (Iterator i = col.iterator(); i.hasNext();) {
T obj = i.next();
if (predicate.filter(obj)) {
i.remove();
}
}
}
使い方:
List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
public boolean filter(MyObject obj) {
return obj.shouldFilter();
}
});
平易で率直なJavaについてはどうですか
List<Customer> list ...;
List<Customer> newList = new ArrayList<>();
for (Customer c : list){
if (c.getName().equals("dd")) newList.add(c);
}
シンプルで読みやすく、簡単です(Androidでも動作します!)Java 8を使用している場合は、簡単な1行で実行できます。
List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());
toList()は静的にインポートされることに注意してください
イテレータではなくコレクション自体をフィルタリングしてもよろしいですか?
org.apache.commons.collections.iterators.FilterIteratorを参照してください
またはApache Commons org.apache.commons.collections4.iterators.FilterIteratorのバージョン4を使用します
Eclipseコレクションを使用して、組み込みの JDKリストとMutableListをフィルタリングする方法を見てみましょう。
List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);
3未満の数値をフィルタリングする場合は、次の出力が予想されます。
List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);
これは、Java 8ラムダをとして使用してフィルタリングする方法ですPredicate
。
Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));
Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));
以下は、匿名の内部クラスをとして使用してフィルタリングする方法ですPredicate
。
Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
public boolean accept(Integer each)
{
return each < 3;
}
};
Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));
ここでは、Predicatesファクトリーを使用してJDKリストとEclipseコレクションの MutableListsをフィルタリングするいくつかの代替方法を示します。
Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));
を受け取るselectWith
メソッドで代わりにPredicates2ファクトリーを使用して、述語にオブジェクトを割り当てないバージョンを次に示しますPredicate2
。
Assert.assertEquals(
selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));
否定的な条件でフィルタリングしたい場合があります。Eclipseコレクションにはと呼ばれる特別なメソッドがありreject
ます。
Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));
このメソッドpartition
は、によって選択され、拒否された要素を含む2つのコレクションを返しPredicate
ます。
PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());
PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());
注:私はEclipseコレクションのコミッターです。
removeIf
プリミティブのリストまたはセットでどのように実行しますか?
ForEach DSLを使用すると、次のように記述できます。
import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;
Collection<String> collection = ...
for (Select<String> each : select(collection)) {
each.yield = each.value.length() > 3;
}
Collection<String> result = $result();
[the、quick、brown、fox、jumps、over、the、lazy、dog]のコレクションを考えると、これは[quick、brown、jumps、over、lazy]、つまりすべての文字列が3文字より長いことになります。
ForEach DSLでサポートされているすべての反復スタイルは
AllSatisfy
AnySatisfy
Collect
Counnt
CutPieces
Detect
GroupedBy
IndexOf
InjectInto
Reject
Select
詳細については、https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEachを参照してください。
GoogleのGuavaライブラリのCollections2.filter(Collection、Predicate)メソッドは、まさにあなたが探しているものを実行します。
以来Javaの9が Collectors.filtering
有効になっています。
public static <T, A, R>
Collector<T, ?, R> filtering(Predicate<? super T> predicate,
Collector<? super T, A, R> downstream)
したがって、フィルタリングは次のようになります。
collection.stream().collect(Collectors.filtering(predicate, collector))
例:
List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
.collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
これは、実際のクロージャーの欠如と相まって、Javaに対する私の最大の不満です。正直なところ、上記のメソッドのほとんどは非常に読みやすく、非常に効率的です。ただし、.Net、Erlangなどで時間を費やした後は、言語レベルで統合されたリスト内包表記により、すべてが非常にきれいになります。言語レベルでの追加なしでは、Javaはこの分野の他の多くの言語と同じようにきれいにすることはできません。
パフォーマンスが大きな懸念事項である場合は、Googleコレクションが最適です(または独自の簡単な述語ユーティリティを作成する)。Lambdaj構文は一部の人にとってはより読みやすいですが、それほど効率的ではありません。
そして、私が書いたライブラリがあります。私はその効率性に関する質問は無視します(そう、それは悪い)......はい、私はその反射に基づいていることをはっきりと知っています。いいえ、実際には使用していませんが、機能します。
LinkedList<Person> list = ......
LinkedList<Person> filtered =
Query.from(list).where(Condition.ensure("age", Op.GTE, 21));
または
LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
JFilter http://code.google.com/p/jfilter/は、要件に最適です。
JFilterは、Java Beanのコレクションを照会するためのシンプルで高性能なオープンソースライブラリです。
主な特徴
私が書いた、拡張反復処理可能クラスをサポートは、コレクションの内容をコピーせずに機能的なアルゴリズムを適用すること。
使用法:
List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }
Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
public Boolean call(Integer n) throws FunctionalException
{
return n % 2 == 0;
}
})
for( int n : filtered )
{
System.out.println(n);
}
上記のコードは実際に実行されます
for( int n : myList )
{
if( n % 2 == 0 )
{
System.out.println(n);
}
}
使用コレクションクエリーエンジン(CQEngine) 。これは、これを実行する最も速い方法です。
ここにいくつかの本当に素晴らしい答えがあります。私は、シンをできるだけシンプルで読みやすいものにしたいと思います。
public abstract class AbstractFilter<T> {
/**
* Method that returns whether an item is to be included or not.
* @param item an item from the given collection.
* @return true if this item is to be included in the collection, false in case it has to be removed.
*/
protected abstract boolean excludeItem(T item);
public void filter(Collection<T> collection) {
if (CollectionUtils.isNotEmpty(collection)) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (excludeItem(iterator.next())) {
iterator.remove();
}
}
}
}
}
単純なJava8以前のソリューション:
ArrayList<Item> filtered = new ArrayList<Item>();
for (Item item : items) if (condition(item)) filtered.add(item);
残念ながら、このソリューションは完全に汎用的ではなく、指定されたコレクションのタイプではなくリストを出力します。また、ライブラリを組み込むか、このコードをラップする関数を作成することは、条件が複雑でない限り、やり過ぎのように思えますが、条件の関数を作成できます。
https://code.google.com/p/joquery/
さまざまな可能性をサポートし、
与えられたコレクション、
Collection<Dto> testList = new ArrayList<>();
タイプの、
class Dto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
フィルタ
Java 7
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property("id").eq().value(1);
Collection<Dto> filtered = query.list();
Java 8
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property(Dto::getId)
.eq().value(1);
Collection<Dto> filtered = query.list();
また、
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.property(Dto::getId).between().value(1).value(2)
.and()
.property(Dto::grtText).in().value(new string[]{"a","b"});
並べ替え(Java 7でも利用可能)
Filter<Dto> query = CQ.<Dto>filter(testList)
.orderBy()
.property(Dto::getId)
.property(Dto::getName)
Collection<Dto> sorted = query.list();
グループ化(Java 7でも利用可能)
GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
.group()
.groupBy(Dto::getId)
Collection<Grouping<Integer,Dto>> grouped = query.list();
結合(Java 7でも使用可能)
与えられた、
class LeftDto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
class RightDto
{
private int id;
private int leftId;
private String text;
public int getId()
{
return id;
}
public int getLeftId()
{
return leftId;
}
public int getText()
{
return text;
}
}
class JoinedDto
{
private int leftId;
private int rightId;
private String text;
public JoinedDto(int leftId,int rightId,String text)
{
this.leftId = leftId;
this.rightId = rightId;
this.text = text;
}
public int getLeftId()
{
return leftId;
}
public int getRightId()
{
return rightId;
}
public int getText()
{
return text;
}
}
Collection<LeftDto> leftList = new ArrayList<>();
Collection<RightDto> rightList = new ArrayList<>();
次のように参加できます
Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
.<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
.on(LeftFyo::getId, RightDto::getLeftId)
.transformDirect(selection -> new JoinedDto(selection.getLeft().getText()
, selection.getLeft().getId()
, selection.getRight().getId())
)
.list();
式
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.exec(s -> s.getId() + 1).eq().value(2);
私の答えはここにワンライナーとして使用して、ケビンウォンからその上に構築CollectionUtils
から春とJava 8 のラムダ式。
CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);
これは、(アスペクトベースのライブラリを使用せずに)私が見たどの代替手段と同じくらい簡潔で読みやすいです
Spring CollectionUtilsは、Spring バージョン4.0.2.RELEASEから利用できます。JDK1.8および言語レベル8以上が必要であることを忘れないでください。
リストに既に存在する値に応じてリストをフィルタリングする必要がありました。たとえば、現在の値よりも小さい値に続くすべての値を削除します。{2 5 3 4 7 5}-> {2 5 7}。または、たとえば、すべての重複を削除するには{3 5 4 2 3 5 6}-> {3 5 4 2 6}。
public class Filter {
public static <T> void List(List<T> list, Chooser<T> chooser) {
List<Integer> toBeRemoved = new ArrayList<>();
leftloop:
for (int right = 1; right < list.size(); ++right) {
for (int left = 0; left < right; ++left) {
if (toBeRemoved.contains(left)) {
continue;
}
Keep keep = chooser.choose(list.get(left), list.get(right));
switch (keep) {
case LEFT:
toBeRemoved.add(right);
continue leftloop;
case RIGHT:
toBeRemoved.add(left);
break;
case NONE:
toBeRemoved.add(left);
toBeRemoved.add(right);
continue leftloop;
}
}
}
Collections.sort(toBeRemoved, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int i : toBeRemoved) {
if (i >= 0 && i < list.size()) {
list.remove(i);
}
}
}
public static <T> void List(List<T> list, Keeper<T> keeper) {
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
if (!keeper.keep(iterator.next())) {
iterator.remove();
}
}
}
public interface Keeper<E> {
boolean keep(E obj);
}
public interface Chooser<E> {
Keep choose(E left, E right);
}
public enum Keep {
LEFT, RIGHT, BOTH, NONE;
}
}
これはこのように使われます。
List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
@Override
public Filter.Keep choose(String left, String right) {
return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
}
});