web-dev-qa-db-ja.com

戻る前にコレクションストリーム内のコレクションストリームをフィルタリングする

背景情報

次のクラスがあります。

保険

public class Insurance {
    ...
}

お客様

public class Customer {
    private List<Insurance> insurances;

    public List<Insurance> getInsurances() {
        return insurances;
    }
    ...
}

CustomerRegistry

public class CustomerRegistry {
    private List<Customer> customers;
    ...
}

また、List<Predicate<T>>を単一のPredicate<T>に縮小するこのヘルパーメソッド:

public Predicate<T> reducePredicates(List<Predicate<T>> predicates) {
    return predicates.stream()
                     .reduce(Predicate::and)
                     .orElse(p -> true);
}

問題

私がやりたいのは、フィルターのリストに一致する顧客に属する、フィルターのリストに一致する保険のリストを取得することです。これが不明確な場合は、以下のコードで明確になります。

メソッドは上記のCustomerRegistryクラス内にあります。

public List<Insurance> findInsurances(List<Predicate<Customer>> cusPredicates,
List<Predicate<Insurance>> insPredicates) {

    List<Insurance> matches = new LinkedList<>();
    customers.stream()
             .filter(reducePredicates(cusPredicates)
             .forEach(cus -> cus.getInsurances()
                               .stream()
                               .filter(reducePredicates(insPredicates))
                               .forEach(cus -> matches.add(cus)))
    return matches;
}

matchesリストなしでこれを行う方法はありますか?一致する保険が直接返されるように(つまり、matchesのような一時的なコレクションに追加されないように)、ある種の削減を実行できますか?

14
Martin M J

FlatMap()を使用します。

customers.stream()
         .filter(reducePredicates(cusPredicates))
         .flatMap(cus -> cus.getInsurances().stream())
         .filter(reducePredicates(insPredicates))
         .collect(Collectors.toList())

または、述語を何度も減らすことを避けるために、次のようにします。

Predicate<Customer> customerPredicate = reducePredicates(cusPredicates);
Predicate<Customer> insurancePredicate = reducePredicates(insPredicates);
List<Insurance> = 
    customers.stream()
             .filter(customerPredicate)
             .flatMap(cus -> cus.getInsurances().stream())
             .filter(insurancePredicate)
             .collect(Collectors.toList())
14
JB Nizet