Filter
You have an array of books but only want the ones that are overdue. You have an array of files but only want the ones that are over a month old. You have an array of songs but only want the ones that have been liked. In all three cases, the big arrays may be winnowed down using the filter pattern.
A filter operation iterates through a collection, asking each item if it meets some criteria. This criteria varies with each task, so it is left as a parameter. Callers pass in a predicate function that considers an item and yields true or false. The items for which the predicate yields true are collected into a new array. Visually, the filter pattern performs this operation:
The filter pattern has this pseudocode implementation:
class Collection
items = ...
function filter(predicate)
keepers = []
for i in 0 to items.size
if predicate(items[i], i)
keepers.push(items[i])
return keepers
Ruby implements the filter pattern in the filter
method of its Array
class. Not having to write the loop and conditional statement saves a lot of noise in these calls:
long_words = words.filter { |word| word.length > 6 }
big_files = files.filter { |file| file.size > 1024 }
safe_urls = urls.filter { |url| url.start_with? 'https' }
If the index is needed in the predicate, with_index
may be called on the iterator returned by filter
. This call keeps only the items at even indices:
evens = items.filter.with_index { |item, i| i % 2 == 0 }
Many languages provide a higher-order filtering mechanism. Once again, the Python community favors list comprehensions. A trailing predicate is added to a list comprehension using the if
keyword:
safe_urls = [url for url in urls if url.startswith('https')]