title: Conditionally Combine Lambdas in Kotlin for Filtering with Multiple Predicates
body: <p>Suppose I have the following predicates as predefined lambdas for a Villager POJO.</p>
  
  <pre><code>    val matchesSearch: (Villager, String) -&gt; Boolean =
          { villager: Villager, query: String -&gt; villager.name.contains(query) }
  
      val matchesGender: (Villager, Int) -&gt; Boolean =
          { villager: Villager, filter: Int -&gt; filter == villager.gender }
  
      val matchesPersonality: (Villager, Int) -&gt; Boolean =
          { villager: Villager, filter: Int -&gt; filter == villager.personality }
  
      val matchesSpecies: (Villager, Int) -&gt; Boolean =
          { villager: Villager, filter: Int -&gt; filter == villager.species }
  
      val matchesHobby: (Villager, Int) -&gt; Boolean =
          { villager: Villager, filter: Int -&gt; filter == villager.hobby }
  </code></pre>
  
  <p>I only want to apply the predicate IF a certain condition is met. For example, only filter by gender if a gender filter has been applied. Or I only want to match against the search query if one has been entered.</p>
  
  <pre><code>fun getVillagersThatMatchQueryAndFilters(list: List&lt;Villager&gt;): List&lt;Villager&gt; {
  
      val conditions = ArrayList&lt;Predicate&lt;Villager&gt;&gt;()
  
      if (searchQuery.isNotEmpty()) {
          // TODO: apply the matchesSearch() predicate lambda
          conditions.add(Predicate { villager -&gt; villager.name.contains(query) })
      }
      if (genderFilter &gt; 0) {
          // TODO: apply the matchesGender() predicate lambda
          conditions.add(Predicate { genderFilter == villager.gender })
      }
      if (personalityFilter &gt; 0) {
          // TODO: apply the matchesPersonality() predicate lambda
          conditions.add(Predicate { personalityFilter == villager.personality })
      }
      if (speciesFilter &gt; 0) {
          // TODO: apply the matchesSpecies() predicate lambda
          conditions.add(Predicate { speciesFilter == villager.species })
      }
      if (hobbyFilter &gt; 0) {
          // TODO: apply the matchesHobby() predicate lambda
          conditions.add(Predicate { hobbyFilter == villager.hobby })
      }
  
      return list.filter {
          // TODO: match on all conditionally applied predicates
          conditions.allPredicatesCombinedWithAnd() // this doesn't actually exist
      }
  }
  </code></pre>
  
  <p>Previously I had done <code>list.filter{ }</code> within each condition and applied the necessary predicate, however, since I could have up to 5 predicates being applied, it is quite terrible for performance as it iterates over the list each time <code>.filter()</code> is called.</p>
  
  <p>Is there a way to programmatically iterate over a <code>List&lt;Predicate&lt;T&gt;&gt;</code> and combine predicates with <code>.and()</code> or <code>&amp;&amp;</code> so that I may apply the filter ONCE? Or if not, how can I <strong>conditionally combine</strong> these predicates?</p>
  
  <p>I would use the final Java example <a href="https://github.com/eugenp/tutorials/blob/master/core-java-modules/core-java-function/src/test/java/com/baeldung/java8/Java8PredicateChainUnitTest.java" rel="nofollow noreferrer">here</a> that uses <code>Predicates.stream()</code> and <code>Collectors</code> but it requires Android API level 24 (higher than my current Android min).</p>
  
  <p><strong>SOLUTION BELOW</strong> - thanks to suggestions from <a href="https://stackoverflow.com/users/1296641/laurence">@Laurence</a> and <a href="https://stackoverflow.com/users/12191177/ir42">@IR42</a></p>
  
  <p><em>Works for &lt; Android API 24</em></p>
  
  <p>Create a list of the lambdas and conditionally add any predicates that you wish to match list items against. Then use <code>Collections.Aggregates.all()</code> method to ensure you are filtering against ALL predicates. (The equivalent of doing <code>pred1.and(pred2).and(etc.)...</code> for all items in the list.)</p>
  
  <p>Huge performance saver if you have a large number of predicates to be filtered against as <code>list.filter()</code> is only called ONCE.</p>
  
  <pre><code>fun getVillagersThatMatchQueryAndFilters(list: List&lt;Villager&gt;): List&lt;Villager&gt; {
  
      val conditions = ArrayList&lt;(Villager) -&gt; Boolean&gt;()
  
      if (searchQuery.isNotEmpty()) {
          conditions.add{ it.name.contains(query) }
      }
      if (genderFilter &gt; 0) {
          conditions.add{ genderFilter == it.gender }
      }
      if (personalityFilter &gt; 0) {
          conditions.add{ personalityFilter == it.personality }
      }
      if (speciesFilter &gt; 0) {
          conditions.add{ speciesFilter == it.species }
      }
      if (hobbyFilter &gt; 0) {
          conditions.add{ hobbyFilter == it.hobby }
      }
  
      return list.filter { candidate -&gt; conditions.all { it(candidate) } }
  }
  </code></pre>