Combine Predicates (and, or)
Problem
Keep the numbers that satisfy this rule: (the number is even AND bigger than k) OR (the number is a multiple of 5). Build the rule from small predicates (even, greater than k, multiple of 5) that you combine with and / or instead of writing one long condition. Print the kept numbers in the original order, separated by spaces (print an empty line if none is kept).
Constraints
- 1 <= n <= 10^5
Examples
Input
8 1 2 3 4 5 6 10 15 3
Output
4 5 6 10 15
Solutions
A predicate is a small function with a yes or no answer. Combining predicates with and, or and negate keeps each rule short, named and reusable. Java's Predicate has these methods built in; in other languages a tiny helper does the same.
/*
* Problem : Filter with a rule.
* Input : n, array, k.
* Output : The kept numbers.
* Approach: Combine predicates.
* Time : O(n)
* Space : O(n)
* Java : 8 or newer.
*/
import java.util.Scanner;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Main {
// This method solves the task. It receives the input and returns the answer.
static int[] solve(int[] a, int k) {
// Step 1: Small predicates, each with one job. Predicate<Integer> is a function that gives true or false.
java.util.function.Predicate<Integer> isEven = value -> value % 2 == 0;
java.util.function.Predicate<Integer> isGreater = value -> value > k;
java.util.function.Predicate<Integer> isMultipleOfFive = value -> value % 5 == 0;
// Step 2: Combine them. and() and or() give new predicates, and the old ones stay unchanged.
java.util.function.Predicate<Integer> keep = isEven.and(isGreater).or(isMultipleOfFive);
// Step 3: Filter the numbers with the combined predicate.
return java.util.Arrays.stream(a).boxed().filter(keep).mapToInt(Integer::intValue).toArray();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int[] a = new int[size];
for (int i = 0; i < size; i++) {
a[i] = scanner.nextInt();
}
int k = scanner.nextInt();
System.out.println(Arrays.stream(solve(a, k)).mapToObj(String::valueOf).collect(Collectors.joining(" ")));
}
}
Hints (1)
- Why is a combined predicate easier to read than one long if?