Skip to main content

Filtering a Collection

Filtering means picking out the elements of a collection that match a condition.

The condition is written as a function that takes one element and returns true (keep it) or false (skip it). Such a function is called a predicate.

Filtering builds a new array. The original array is not changed.

PHP has a built-in filter: array_filter(). It takes an array and a predicate and returns a new array with the elements the predicate says yes to. The short arrow-function syntax fn($w) => ... keeps the call compact.

One thing to remember: array_filter() keeps the original keys. When you want a clean list numbered from 0 again, wrap the result in array_values().


Filter by Predicate

The simplest way to filter is to pass the array and a predicate to array_filter(). By default the predicate receives only the value.

With the flag ARRAY_FILTER_USE_BOTH the predicate receives the value and the key, so an associative array can be filtered by both at once. The flag ARRAY_FILTER_USE_KEY passes only the key.

In a plain list the keys are the positions 0, 1, 2, …, so ARRAY_FILTER_USE_BOTH also lets a condition use the index of the element.

To keep the elements that do not match, put ! in front of the condition. PHP has no separate filterNot.

A PHP array can hold values of different types. is_string() checks whether a value is a string, and $v !== null skips the entries that hold no value.

Filter an array

Keep only the words that are longer than 3 letters. The condition strlen($w) > 3 is passed to array_filter() as an arrow function.

array_filter() keeps the original keys, so the kept words still sit at 2 and 3 and json_encode() prints {"2":"three","3":"four"}. After array_values() the keys start at 0 again and the same call prints the clean list ["three","four"].

Prompt
Write a PHP script with the words one, two, three, four in an array. Keep the words longer than 3 letters with array_filter and an arrow function. Print the filtered array with json_encode to show that the original keys survive, then print it again after array_values has renumbered the keys.
Output: PHP script
Filter an array

Filter an associative array

The pairs whose key ends with "1" and whose value is greater than 10 are kept. The flag ARRAY_FILTER_USE_BOTH makes array_filter() hand both the value and the key to the predicate, and str_ends_with() checks the end of the key.

Prompt
Create an associative array from the keys key1, key2, key3, key11 to the values 1, 2, 3, 11. Use array_filter with the ARRAY_FILTER_USE_BOTH flag to keep only the pairs whose key ends with "1" and whose value is greater than 10. Print the result with json_encode.
Output: PHP script
Filter an associative array

Filter using the index

In the list the key of each word is its position. With ARRAY_FILTER_USE_BOTH the predicate sees the word and its index. A word is kept only when its index is not 0 and it has fewer than 5 letters.

Prompt
Take the words one, two, three, four. Use array_filter with ARRAY_FILTER_USE_BOTH so the predicate sees the position too. Keep a word only if its position is not 0 and it is shorter than 5 letters, then reindex with array_values and print the result with json_encode.
Output: PHP script
Filter using the index

Filter with a negated condition

Drop the words with 3 letters or fewer. The condition strlen($w) = 3 is negated with !, so only the longer words stay.

Prompt
Take the words one, two, three, four. Use array_filter, but negate the condition with ! so that words with 3 letters or fewer are dropped. Reindex with array_values and print the result with json_encode.
Output: PHP script
Filter with a negated condition

Filter by type

The array holds null, a number, two strings and a float. The callback is_string(...) is the built-in function itself, passed with the first-class callable syntax. Each kept string is printed in upper case.

Prompt
Make an array holding null, 1, "two", 3.5 and "four". Use array_filter with is_string(...) to keep only the strings. Print each kept string in upper case, one per line.
Output: PHP script
Filter by type

Filter out null values

The array holds strings and null entries. The explicit test $v !== null keeps the real values. Do not call array_filter() without a callback here: it would drop every "falsy" value, including 0, "" and even the string "0".

Prompt
Make an array that holds null, "one", null and "two". Keep the values that are not null with array_filter and an explicit !== null test. Reindex with array_values and print the result with json_encode.
Output: PHP script
Filter out null values

Partition

Sometimes you want both groups: the elements that match and the ones that do not.

PHP has no built-in partition. One foreach loop does it: each element is appended with []= to either the $match array or the $rest array. After the loop you have both arrays.

Split an array in two

Words longer than 3 letters go into $match; all the others go into $rest. Both arrays are printed.

Prompt
Write a PHP script that splits the words one, two, three, four into two arrays with one foreach loop: words longer than 3 letters go into match, all the others into rest. Print both arrays with json_encode.
Output: PHP script
Split an array in two

Test Predicates

Sometimes you do not need the matching elements, only a yes or no answer.

  • any: does at least one element pass the test? array_any(), new in PHP 8.4, answers this and stops at the first match.
  • none: does no element pass the test? Put ! in front of array_any().
  • all: does every element pass the test? array_all(), also new in PHP 8.4, answers this.

Without a condition, "any element at all?" is count($arr) > 0 and "no element at all?" is count($arr) === 0.

On an empty array, array_all() returns true. There is no element that fails the test, so the test is never broken. This is called vacuous truth.

The examples print the answers with json_encode(), which turns the booleans into the readable text true and false.

any

Check whether at least one word ends with "e", then check whether the array has any element at all. array_any() stops as soon as "one" passes — the other words are not tested.

Prompt
Take the words one, two, three, four. Use array_any to check whether at least one word ends with "e" and print the answer with json_encode. Then print whether the array has any element at all by checking count is greater than 0.
Output: PHP script
any

none

Check that no word ends with "a", then check whether the array is empty. array_any() finds nothing and returns false, so the ! turns it into true.

Prompt
Take the words one, two, three, four. Use ! with array_any to check that no word ends with "a" and print the answer with json_encode. Then print whether the array is empty by checking count equals 0.
Output: PHP script
none

all

Check whether every word ends with "e". array_all() stops at "two" and returns false. On an empty array it returns true.

Prompt
Take the words one, two, three, four. Use array_all to check whether every word ends with "e" and print the answer with json_encode. Then call array_all on an empty array with the same condition and print the answer.
Output: PHP script
all