Union of Filters

Step 4: Union of Filters

Two Bloom filters with the same size and hash configuration can be merged with a bitwise OR. The result contains every item either one had. This is how you combine filters built in parallel (e.g. per-shard) into one.

Implement:

  • union(other): return a new BloomFilter (same size, num_hashes, hash_fn) whose bits are the OR of self and other

The union must report contains True for items added to either source filter.

Hints
Starter code
import hashlib


def _default_hash(item, i, size):
    return int(hashlib.md5(f"{i}:{item}".encode()).hexdigest(), 16) % size


class BloomFilter:
    def __init__(self, size, num_hashes, hash_fn=None):
        self.size = size
        self.num_hashes = num_hashes
        self.hash_fn = hash_fn
        self._bits = bytearray(size)

    def _indices(self, item):
        if self.hash_fn is not None:
            return [self.hash_fn(item, i) for i in range(self.num_hashes)]
        return [_default_hash(item, i, self.size) for i in range(self.num_hashes)]

    def add(self, item):
        for idx in self._indices(item):
            self._bits[idx] = 1

    def contains(self, item):
        return all(self._bits[idx] for idx in self._indices(item))

    def count_set_bits(self):
        return sum(self._bits)

    def union(self, other):
        """Return a new BloomFilter whose bits are the OR of self and other."""
        # TODO: build a fresh filter carrying the same size, num_hashes and hash_fn as
        # this one, then fill its bit array so a position ends up set whenever either
        # source filter has that position set. Hand back that new filter and leave the
        # bits of both self and other exactly as you found them.
        pass
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.