Filter

Dear Computer

Chapter 4: Functions

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:

An array of triangles filter into an array of right triangles

The filter pattern has this pseudocode implementation:

Pseudocode
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:

Ruby
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:

Ruby
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:

Python
safe_urls = [url for url in urls if url.startswith('https')]
← MapFold →