The find Algorithm and Searching for Values
A predicate is a specified requirement or condition that an element must fulfill, and an algorithm can accept it as a parameter instead of building the action in.
Finding the First Item That Qualifies
Imagine a warehouse inventory in which each item name is paired with a stock count. A manager asks: which is the first item with more than 42 units on hand? Answering that question means checking entries one at a time until one of them meets a rule. Nothing about this question is a plain equality check. The manager is not looking for one exact count. The condition is a rule that changes from one question to the next.
What do you think happens?
Given the inventory Widgets 12, Gears 40, Bolts 57, Nuts 30, which entry does the manager's search return?
Reveal answer
Bolts, because 57 is the first count greater than 42. Widgets (12) and Gears (40) fail the rule, so the search does not stop there.
The search does not need to look at every entry. It stops at the first one that satisfies the rule, so Nuts is never reached.
This article looks at how that changing condition can be handed to an algorithm as an input. When the condition is an input, the same search routine can answer many different questions. We will return to the inventory example throughout, following what happens to each entry as it is examined.
What a Predicate Is
A predicate is a specified requirement or condition that an element must fulfill. An algorithm can accept a predicate as a parameter instead of having the action built into its own logic.
A predicate must return a yes or no answer for each element it is given. In the inventory search, the predicate is the rule 'more than 42 units'. For each entry, the rule answers yes or no. The search usually stops at the first element that satisfies it, so the predicate is the part that decides when the search is finished.
Why does an algorithm need a predicate at all? Some algorithms have a fixed action built into their logic. They always do the same thing to each element they visit, which works well when the task never changes. In practice the task often differs from one call to the next. A search for a count above 42 uses the same looping logic as a search for a count above 100. The only difference is the rule being applied. Writing a separate search routine for each rule would repeat the same looping logic again and again. A predicate removes that repetition by letting the caller supply the rule.
Built-In Action Versus Supplied Action
There are two ways an algorithm can decide what to do with each element. In the first, the action is built in. The algorithm always performs the same test, and every call uses that same test. In the second, the action is supplied by the caller as a parameter. The algorithm keeps its looping and visiting logic, and the caller provides the piece that decides what each element must satisfy. The supplied piece is the part that varies between calls, and that is what makes the algorithm reusable.
Replacing the threshold, or replacing the whole test with a different condition, changes only the question asked at the decision point. Visiting elements in order and stopping on a match is reused unchanged. Read the comparison as two columns: the left column is fixed, and the right column is what a caller can swap.
Why a Map Hands the Predicate a Pair
A map stores associations between keys and values. To search a map with a predicate, we need to know what the algorithm actually sees as its elements. A map gives access to its contents as a sequence of (key, value) pairs. In C++ terms, a map<string,int> presents its elements as pair<const string,int> objects. The string part is the key, which the map treats as fixed once an entry exists. The int part is the value.
The predicate does not receive a bare integer when searching this kind of map. It receives a whole pair, so the condition must look at the value portion of that pair to decide whether it qualifies. A predicate that ignores this structure will not behave the way the reader expects.
Tracing the Search Over Pairs
The source describes a search of a map<string,int> for the first value larger than 42. The search examines pair<const string,int> elements in sequence and tests the int in each pair against the requirement that it be greater than 42. Here is the inventory traced as the search walks through it. Each pair is a name and a count, and the test is whether the count satisfies $value > 42$.
Finding the first count above 42
Search the inventory pairs Widgets 12, Gears 40, Bolts 57, Nuts 30 for the first pair whose int value is greater than 42.
- 1Start at the beginning
The search takes the first pair in the sequence, Widgets with value 12, and hands the whole pair to the predicate.
- 2Test Widgets
The predicate looks at the int part, 12, and asks whether $12 > 42$. The answer is no, so the search moves on.
- 3Test Gears
The next pair is Gears with value 40. The predicate asks whether $40 > 42$. The answer is no, so the search moves on.
- 4Test Bolts
The next pair is Bolts with value 57. The predicate asks whether $57 > 42$. The answer is yes, so the search stops at this pair.
- 5Nuts is never tested
Because the search already stopped at Bolts, the pair Nuts, 30, is not examined. The search usually stops at the first element that satisfies the requirement.
The search returns the Bolts pair, the first entry with a count greater than 42.
The Predicate's Decision Cycle
When an algorithm's action is a parameter, control moves in a predictable pattern. The algorithm starts at the beginning of the sequence, asks the supplied requirement about the current element, and chooses one of two paths based on the answer. A yes answer ends the search at that element. A no answer advances to the next element and repeats the question. The diagram below traces this cycle for a single pair.
The predicate is the only part of this cycle that knows the particular threshold. The traversal itself stays the same no matter what condition is supplied. This is why the same loop can answer a question about 42 today and a question about 100 tomorrow.
Mistakes When Writing a Predicate
Common mistake Testing only the key
What it looks likeA predicate that asks whether the name Bolts is greater than 42, when the rule is about the count.
Why it failsThe predicate must examine the value portion of the pair, which is the int. The key is a string and does not carry the count the rule is about.
Do this insteadLook at the int part of the pair, such as checking whether the value is greater than 42.
Common mistake Expecting a bare value instead of a pair
What it looks likeA predicate written as if it receives just the number 57, but the search hands it the whole pair Bolts, 57.
Why it failsA map gives its elements as pair objects, so the predicate receives the pair. Code written for a bare integer will not behave as expected.
Do this insteadRead the pair's value portion before applying the condition.
Common mistake Using an equality test when the rule is a range or threshold
What it looks likeChecking whether the count equals 42 when the manager asked for counts more than 42.
Why it failsA plain equality check finds one exact count. The manager's question is a changing condition, so the predicate must express that condition.
Do this insteadWrite the test that matches the requirement, such as greater than 42.
Common mistake Forgetting that the predicate must return a yes or no answer for every element, so the search has a clear rule at each step
Practice Tracing a New Threshold
Using the same inventory pairs Widgets 12, Gears 40, Bolts 57, Nuts 30, trace a search for the first pair whose int value is greater than 100. For each pair, write the predicate's answer, and state at which pair the search stops or whether it reaches the end of the sequence without a match.
Hints
- The predicate tests the int part of each pair, not the key.
- Keep the same loop: start at Widgets and move forward one pair at a time.
- Only the threshold changed, so the traversal steps are the same as before.
Reviewing the Search Pattern
- 1A predicate is a yes or no requirement that each element must fulfill, and an algorithm can accept it as a parameter.
- 2The algorithm keeps the looping and stopping logic fixed, and the supplied predicate decides only the test at the decision point.
- 3When searching a map, the predicate receives a whole (key, value) pair, so it must examine the value portion.
- 4Common mistakes include testing only the key, expecting a bare value instead of a pair, and using an equality test when the rule is a threshold.
Key Takeaways
- A predicate is a specified requirement or condition that an element must fulfill, and an algorithm can accept it as a parameter instead of building the action in.
- The algorithm keeps the same loop and stopping logic, while the supplied predicate changes only the test at the decision point.
- A map's elements are (key, value) pairs, so a predicate searching a map must inspect the value portion of the pair it receives.
- Typical predicate errors are testing only the key, expecting a bare value instead of a pair, and using an equality test where the requirement is a threshold.